📄 containerbuilder.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.opensymphony.xwork2.inject;import java.lang.reflect.Member;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import java.util.logging.Logger;/** * Builds a dependency injection {@link Container}. The combination of * dependency type and name uniquely identifies a dependency mapping; you can * use the same name for two different types. Not safe for concurrent use. * * <p>Adds the following factories by default: * * <ul> * <li>Injects the current {@link Container}. * <li>Injects the {@link Logger} for the injected member's declaring class. * </ul> * * @author crazybob@google.com (Bob Lee) */public final class ContainerBuilder { final Map<Key<?>, InternalFactory<?>> factories = new HashMap<Key<?>, InternalFactory<?>>(); final List<InternalFactory<?>> singletonFactories = new ArrayList<InternalFactory<?>>(); final List<Class<?>> staticInjections = new ArrayList<Class<?>>(); boolean created; private static final InternalFactory<Container> CONTAINER_FACTORY = new InternalFactory<Container>() { public Container create(InternalContext context) { return context.getContainer(); } }; private static final InternalFactory<Logger> LOGGER_FACTORY = new InternalFactory<Logger>() { public Logger create(InternalContext context) { Member member = context.getExternalContext().getMember(); return member == null ? Logger.getAnonymousLogger() : Logger.getLogger(member.getDeclaringClass().getName()); } }; /** * Constructs a new builder. */ public ContainerBuilder() { // In the current container as the default Container implementation. factories.put(Key.newInstance(Container.class, Container.DEFAULT_NAME), CONTAINER_FACTORY); // Inject the logger for the injected member's declaring class. factories.put(Key.newInstance(Logger.class, Container.DEFAULT_NAME), LOGGER_FACTORY); } /** * Maps a dependency. All methods in this class ultimately funnel through * here. */ private <T> ContainerBuilder factory(final Key<T> key, InternalFactory<? extends T> factory, Scope scope) { ensureNotCreated(); checkKey(key); final InternalFactory<? extends T> scopedFactory = scope.scopeFactory(key.getType(), key.getName(), factory); factories.put(key, scopedFactory); if (scope == Scope.SINGLETON) { singletonFactories.add(new InternalFactory<T>() { public T create(InternalContext context) { try { context.setExternalContext(ExternalContext.newInstance( null, key, context.getContainerImpl())); return scopedFactory.create(context); } finally { context.setExternalContext(null); } } }); } return this; } /** * Ensures a key isn't already mapped. */ private void checkKey(Key<?> key) { if (factories.containsKey(key)) { throw new DependencyException( "Dependency mapping for " + key + " already exists."); } } /** * Maps a factory to a given dependency type and name. * * @param type of dependency * @param name of dependency * @param factory creates objects to inject * @param scope scope of injected instances * @return this builder */ public <T> ContainerBuilder factory(final Class<T> type, final String name, final Factory<? extends T> factory, Scope scope) { InternalFactory<T> internalFactory = new InternalFactory<T>() { public T create(InternalContext context) { try { Context externalContext = context.getExternalContext(); return factory.create(externalContext); } catch (Exception e) { throw new RuntimeException(e); } } public String toString() { return new LinkedHashMap<String, Object>() {{ put("type", type); put("name", name); put("factory", factory); }}.toString(); } }; return factory(Key.newInstance(type, name), internalFactory, scope); } /** * Convenience method. Equivalent to {@code factory(type, * Container.DEFAULT_NAME, factory, scope)}. * * @see #factory(Class, String, Factory, Scope) */ public <T> ContainerBuilder factory(Class<T> type, Factory<? extends T> factory, Scope scope) { return factory(type, Container.DEFAULT_NAME, factory, scope); } /** * Convenience method. Equivalent to {@code factory(type, name, factory, * Scope.DEFAULT)}. * * @see #factory(Class, String, Factory, Scope) */ public <T> ContainerBuilder factory(Class<T> type, String name, Factory<? extends T> factory) { return factory(type, name, factory, Scope.DEFAULT); } /** * Convenience method. Equivalent to {@code factory(type, * Container.DEFAULT_NAME, factory, Scope.DEFAULT)}. * * @see #factory(Class, String, Factory, Scope) */ public <T> ContainerBuilder factory(Class<T> type, Factory<? extends T> factory) { return factory(type, Container.DEFAULT_NAME, factory, Scope.DEFAULT); } /** * Maps an implementation class to a given dependency type and name. Creates * instances using the container, recursively injecting dependencies. * * @param type of dependency * @param name of dependency * @param implementation class * @param scope scope of injected instances * @return this builder */ public <T> ContainerBuilder factory(final Class<T> type, final String name, final Class<? extends T> implementation, final Scope scope) { // This factory creates new instances of the given implementation. // We have to lazy load the constructor because the Container // hasn't been created yet. InternalFactory<? extends T> factory = new InternalFactory<T>() { volatile ContainerImpl.ConstructorInjector<? extends T> constructor; @SuppressWarnings("unchecked") public T create(InternalContext context) { if (constructor == null) { this.constructor = context.getContainerImpl().getConstructor(implementation); } return (T) constructor.construct(context, type); } public String toString() { return new LinkedHashMap<String, Object>() {{ put("type", type); put("name", name); put("implementation", implementation); put("scope", scope); }}.toString(); } }; return factory(Key.newInstance(type, name), factory, scope); } /** * Maps an implementation class to a given dependency type and name. Creates * instances using the container, recursively injecting dependencies. * * <p>Sets scope to value from {@link Scoped} annotation on the * implementation class. Defaults to {@link Scope#DEFAULT} if no annotation * is found. * * @param type of dependency * @param name of dependency * @param implementation class * @return this builder */ public <T> ContainerBuilder factory(final Class<T> type, String name, final Class<? extends T> implementation) { Scoped scoped = implementation.getAnnotation(Scoped.class); Scope scope = scoped == null ? Scope.DEFAULT : scoped.value(); return factory(type, name, implementation, scope); } /** * Convenience method. Equivalent to {@code factory(type, * Container.DEFAULT_NAME, implementation)}. * * @see #factory(Class, String, Class) */ public <T> ContainerBuilder factory(Class<T> type, Class<? extends T> implementation) { return factory(type, Container.DEFAULT_NAME, implementation); } /** * Convenience method. Equivalent to {@code factory(type, * Container.DEFAULT_NAME, type)}. * * @see #factory(Class, String, Class) */ public <T> ContainerBuilder factory(Class<T> type) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -