⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 binderimpl.java

📁 Guice是轻量级的依赖注入框架。简而言之
💻 JAVA
字号:
/** * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.google.inject;import com.google.inject.InjectorImpl.SingleMemberInjector;import com.google.inject.Key.AnnotationStrategy;import static com.google.inject.Scopes.SINGLETON;import com.google.inject.matcher.Matcher;import com.google.inject.spi.Message;import com.google.inject.spi.SourceProviders;import com.google.inject.util.Annotations;import static com.google.inject.util.Objects.nonNull;import com.google.inject.util.StackTraceElements;import com.google.inject.util.Stopwatch;import java.lang.annotation.Annotation;import java.lang.reflect.Member;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;import java.util.HashMap;import java.util.HashSet;import java.util.List;import java.util.Map;import java.util.Set;import java.util.logging.Level;import java.util.logging.Logger;import org.aopalliance.intercept.MethodInterceptor;/** * Builds a dependency injection {@link Injector}. Binds {@link Key}s to * implementations. * * * @author crazybob@google.com (Bob Lee) */class BinderImpl implements Binder {  static {    SourceProviders.skip(BinderImpl.class);  }  private static final Logger logger      = Logger.getLogger(BinderImpl.class.getName());  final List<BindingBuilderImpl<?>> bindingBuilders      = new ArrayList<BindingBuilderImpl<?>>();  final List<ConstantBindingBuilderImpl> constantBindingBuilders      = new ArrayList<ConstantBindingBuilderImpl>();  final Map<Class<? extends Annotation>, Scope> scopes =      new HashMap<Class<? extends Annotation>, Scope>();  final List<StaticInjection> staticInjections      = new ArrayList<StaticInjection>();  InjectorImpl injector;  final Stage stage;  final Collection<Message> errorMessages = new ArrayList<Message>();  private static final InternalFactory<Injector> INJECTOR_FACTORY      = new InternalFactory<Injector>() {    public Injector get(InternalContext context) {      return context.getInjectorImpl();    }    public String toString() {      return "Provider<Injector>";    }  };  private static final InternalFactory<Logger> LOGGER_FACTORY      = new InternalFactory<Logger>() {    // not test-covered?    public Logger get(InternalContext context) {      Member member = context.getExternalContext().getMember();      return member == null          ? Logger.getAnonymousLogger()          : Logger.getLogger(member.getDeclaringClass().getName());    }    public String toString() {      return "Provider<Logger>";    }  };  final ProxyFactoryBuilder proxyFactoryBuilder;  /**   * Constructs a new builder.   *   * @param stage we're running in. If the stage is {@link Stage#PRODUCTION},   *  we will eagerly load singletons.   */  public BinderImpl(Stage stage) {    bindScope(Singleton.class, SINGLETON);    bind(Injector.class).to(INJECTOR_FACTORY);    bind(Logger.class).to(LOGGER_FACTORY);    bind(Stage.class).toInstance(stage);    this.proxyFactoryBuilder = new ProxyFactoryBuilder();    this.stage = stage;  }  /**   * Constructs a new builder for a development environment (see   * {@link Stage#DEVELOPMENT}).   */  public BinderImpl() {    this(Stage.DEVELOPMENT);  }  public Stage currentStage() {    return stage;  }  final List<CreationListener> creationListeners      = new ArrayList<CreationListener>();  final List<CreationListener> instanceInjectors      = new ArrayList<CreationListener>();  interface CreationListener {    void notify(InjectorImpl injector);  }  public void bindInterceptor(Matcher<? super Class<?>> classMatcher,      Matcher<? super Method> methodMatcher, MethodInterceptor... interceptors) {    proxyFactoryBuilder.intercept(classMatcher, methodMatcher, interceptors);  }  public void bindScope(Class<? extends Annotation> annotationType,      Scope scope) {    if (!Scopes.isScopeAnnotation(annotationType)) {      addError(StackTraceElements.forType(annotationType),          ErrorMessages.MISSING_SCOPE_ANNOTATION);      // Go ahead and bind anyway so we don't get collateral errors.    }    if (!Annotations.isRetainedAtRuntime(annotationType)) {      addError(StackTraceElements.forType(annotationType),          ErrorMessages.MISSING_RUNTIME_RETENTION, source());      // Go ahead and bind anyway so we don't get collateral errors.    }    Scope existing = scopes.get(nonNull(annotationType, "annotation type"));    if (existing != null) {      addError(source(), ErrorMessages.DUPLICATE_SCOPES, existing,          annotationType, scope);    }    else {      scopes.put(annotationType, nonNull(scope, "scope"));    }  }  public <T> BindingBuilderImpl<T> bind(Key<T> key) {    BindingBuilderImpl<T> builder =        new BindingBuilderImpl<T>(this, key, source());    bindingBuilders.add(builder);    return builder;  }  public <T> BindingBuilderImpl<T> bind(TypeLiteral<T> typeLiteral) {    return bind(Key.get(typeLiteral));  }  public <T> BindingBuilderImpl<T> bind(Class<T> clazz) {    return bind(Key.get(clazz));  }  public ConstantBindingBuilderImpl bindConstant() {    ConstantBindingBuilderImpl constantBuilder        = new ConstantBindingBuilderImpl(this, source());    constantBindingBuilders.add(constantBuilder);    return constantBuilder;  }  public void requestStaticInjection(Class<?>... types) {    staticInjections.add(new StaticInjection(source(), types));  }  public void install(Module module) {    module.configure(this);  }  public void addError(String message, Object... arguments) {    configurationErrorHandler.handle(source(), message, arguments);  }  public void addError(Throwable t) {    Object source = source();    String className = t.getClass().getSimpleName();    String message = ErrorMessages.getRootMessage(t);    String logMessage = String.format(        ErrorMessages.EXCEPTION_REPORTED_BY_MODULE, message);    logger.log(Level.INFO, logMessage, t);    addError(source, ErrorMessages.EXCEPTION_REPORTED_BY_MODULE_SEE_LOG, message);  }  void addError(Object source, String message, Object... arguments) {    configurationErrorHandler.handle(source, message, arguments);  }  void addError(Object source, String message) {    configurationErrorHandler.handle(source, message);  }  /**   * Adds an error message to be reported at creation time.   */  void add(Message errorMessage) {    errorMessages.add(errorMessage);  }  final Stopwatch stopwatch = new Stopwatch();  /**   * Creates a {@link Injector} instance. Injects static members for classes   * which were registered using {@link #requestStaticInjection(Class...)}.   *   * @throws CreationException if configuration errors are found. The   *     expectation is that the application will log this exception and exit.   * @throws IllegalStateException if called more than once   */  Injector createInjector() throws CreationException {    stopwatch.resetAndLog(logger, "Configuration");    Map<Key<?>, BindingImpl<?>> bindings = new HashMap<Key<?>, BindingImpl<?>>();    injector = new InjectorImpl(        proxyFactoryBuilder.create(), bindings, scopes);    injector.setErrorHandler(configurationErrorHandler);    createConstantBindings();    // Commands to execute before returning the Injector instance.    final List<ContextualCallable<Void>> preloaders        = new ArrayList<ContextualCallable<Void>>();    createBindings(preloaders);    stopwatch.resetAndLog(logger, "Binding creation");    injector.index();    stopwatch.resetAndLog(logger, "Binding indexing");    for (CreationListener creationListener : creationListeners) {      creationListener.notify(injector);    }    stopwatch.resetAndLog(logger, "Validation");    for (StaticInjection staticInjection : staticInjections) {      staticInjection.createMemberInjectors(injector);    }    stopwatch.resetAndLog(logger, "Static validation");    // Blow up if we encountered errors.    if (!errorMessages.isEmpty()) {      throw new CreationException(errorMessages);    }    // Switch to runtime error handling.    injector.setErrorHandler(new RuntimeErrorHandler());    // Inject static members.    for (StaticInjection staticInjection : staticInjections) {      staticInjection.runMemberInjectors(injector);    }    stopwatch.resetAndLog(logger, "Static member injection");    // Inject pre-existing instances.    for (CreationListener instanceInjector : instanceInjectors) {      instanceInjector.notify(injector);    }    stopwatch.resetAndLog(logger, "Instance injection");    // Run preloading commands.    runPreloaders(injector, preloaders);    stopwatch.resetAndLog(logger, "Preloading");    return injector;  }  private void runPreloaders(InjectorImpl injector,      final List<ContextualCallable<Void>> preloaders) {    injector.callInContext(new ContextualCallable<Void>() {      public Void call(InternalContext context) {        for (ContextualCallable<Void> preloader : preloaders) {          preloader.call(context);        }        return null;      }    });  }  private void createBindings(List<ContextualCallable<Void>> preloaders) {    for (BindingBuilderImpl<?> builder : bindingBuilders) {      createBinding(builder, preloaders);    }  }  private <T> void createBinding(BindingBuilderImpl<T> builder,      List<ContextualCallable<Void>> preloaders) {    final Key<T> key = builder.getKey();    final InternalFactory<? extends T> factory        = builder.getInternalFactory(injector);    BindingImpl<?> binding        = BindingImpl.newInstance(injector, key, builder.getSource(), factory);    putBinding(binding);    // Register to preload if necessary.    boolean preload = stage == Stage.PRODUCTION;    if (builder.isSingletonScoped()) {      if (preload || builder.shouldPreload()) {        preloaders.add(new BindingPreloader(key, factory));      }    }    else {      if (builder.shouldPreload()) {        addError(builder.getSource(), ErrorMessages.PRELOAD_NOT_ALLOWED);      }    }  }  private void createConstantBindings() {    for (ConstantBindingBuilderImpl builder : constantBindingBuilders) {      createConstantBinding(builder);    }  }  private void createConstantBinding(ConstantBindingBuilderImpl builder) {    if (builder.hasValue()) {      putBinding(builder.createBinding(injector));    }    else {      addError(builder.getSource(), ErrorMessages.MISSING_CONSTANT_VALUE);    }  }  private static Set<Class<?>> FORBIDDEN_TYPES = forbiddenTypes();  private static Set<Class<?>> forbiddenTypes() {    Set<Class<?>> set = new HashSet<Class<?>>();    Collections.addAll(set,        // It's unfortunate that we have to maintain a blacklist of specific        // classes, but we can't easily block the whole package because of        // all our unit tests.        AbstractModule.class,        Binder.class,        Binding.class,        Key.class,        Module.class,        Provider.class,        Scope.class,        TypeLiteral.class);    return Collections.unmodifiableSet(set);  }  void putBinding(BindingImpl<?> binding) {    Key<?> key = binding.getKey();    Map<Key<?>, BindingImpl<?>> bindings = injector.internalBindings();    Binding<?> original = bindings.get(key);    Class<?> rawType = key.getRawType();    if (FORBIDDEN_TYPES.contains(rawType)) {      addError(binding.getSource(), ErrorMessages.CANNOT_BIND_TO_GUICE_TYPE,          rawType.getSimpleName());      return;    }    if (bindings.containsKey(key)) {      addError(binding.getSource(), ErrorMessages.BINDING_ALREADY_SET, key,          original.getSource());    }    else {      bindings.put(key, binding);    }  }  /**   * Gets the current source.   */  Object source() {    return SourceProviders.defaultSource();      }  ErrorHandler configurationErrorHandler = new AbstractErrorHandler() {    public void handle(Object source, String message) {      add(new Message(source, message));    }  };  /**   * Handles errors after the injector is created.   */  static class RuntimeErrorHandler extends AbstractErrorHandler {    static ErrorHandler INSTANCE = new RuntimeErrorHandler();    public void handle(Object source, String message) {      throw new ConfigurationException("Error at " + source + " " + message);    }  }  /**   * A requested static injection.   */  class StaticInjection {    final Object source;    final Class<?>[] types;    final List<SingleMemberInjector> memberInjectors        = new ArrayList<SingleMemberInjector>();    public StaticInjection(Object source, Class<?>[] types) {      this.source = source;      this.types = types;    }    void createMemberInjectors(final InjectorImpl injector) {      injector.withDefaultSource(source,          new Runnable() {            public void run() {              for (Class<?> clazz : types) {                injector.addSingleInjectorsForFields(                    clazz.getDeclaredFields(), true, memberInjectors);                injector.addSingleInjectorsForMethods(                    clazz.getDeclaredMethods(), true, memberInjectors);              }            }          });    }    void runMemberInjectors(InjectorImpl injector) {      injector.callInContext(new ContextualCallable<Void>() {        public Void call(InternalContext context) {          for (SingleMemberInjector injector : memberInjectors) {            injector.inject(context, null);          }          return null;        }      });    }  }  static class BindingPreloader implements ContextualCallable<Void> {    private final Key<?> key;    private final InternalFactory<?> factory;    public BindingPreloader(Key<?> key, InternalFactory<?> factory) {      this.key = key;      this.factory = factory;    }    public Void call(InternalContext context) {      ExternalContext<?> externalContext          = ExternalContext.newInstance(null, key, context.getInjectorImpl());      context.setExternalContext(externalContext);      try {        factory.get(context);        return null;      }      finally {        context.setExternalContext(null);      }    }  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -