标签:struts2 struts2初始化 容器 container containerbuilder
在上一篇struts2源码学习之初始化(二)中已经详细介绍了Dispatcher的初始化工作,只差最后一点,容器的创建。这一篇就仔细介绍容器的创建过程,初始化过程以及容器的作用。还是先从源码入手,上一篇已经分析到了Dispatcher类的init()的这段代码:
Container container = init_PreloadConfiguration(); container.inject(this); init_CheckWebLogicWorkaround(container);
private Container init_PreloadConfiguration() { Configuration config = configurationManager.getConfiguration(); Container container = config.getContainer(); boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD)); LocalizedTextUtil.setReloadBundles(reloadi18n); ContainerHolder.store(container); return container; }
先看ConfigurationManager类的getConfiguration()方法:
public synchronized Configuration getConfiguration() { if (configuration == null) { setConfiguration(createConfiguration(defaultFrameworkBeanName)); try { configuration.reloadContainer(getContainerProviders()); } catch (ConfigurationException e) { setConfiguration(null); throw new ConfigurationException("Unable to load configuration.", e); } } else { conditionalReload(); } return configuration; }
protected Configuration createConfiguration(String beanName) { return new DefaultConfiguration(beanName); }
public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException { packageContexts.clear(); loadedFileNames.clear(); List<PackageProvider> packageProviders = new ArrayList<PackageProvider>(); ContainerProperties props = new ContainerProperties();//封装配置文件中声明的常量 ContainerBuilder builder = new ContainerBuilder(); Container bootstrap = createBootstrapContainer(providers); for (final ContainerProvider containerProvider : providers) { bootstrap.inject(containerProvider); containerProvider.init(this); containerProvider.register(builder, props); } props.setConstants(builder); builder.factory(Configuration.class, new Factory<Configuration>() { public Configuration create(Context context) throws Exception { return DefaultConfiguration.this; } }); ActionContext oldContext = ActionContext.getContext(); try { // Set the bootstrap container for the purposes of factory creation setContext(bootstrap); container = builder.create(false); setContext(container); objectFactory = container.getInstance(ObjectFactory.class); // Process the configuration providers first for (final ContainerProvider containerProvider : providers) { if (containerProvider instanceof PackageProvider) { container.inject(containerProvider); ((PackageProvider)containerProvider).loadPackages(); packageProviders.add((PackageProvider)containerProvider); } } // Then process any package providers from the plugins Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class); for (String name : packageProviderNames) { PackageProvider provider = container.getInstance(PackageProvider.class, name); provider.init(this); provider.loadPackages(); packageProviders.add(provider); } rebuildRuntimeConfiguration(); } finally { if (oldContext == null) { ActionContext.setContext(null); } } return packageProviders; }
ok,这个方法中可说的地方是在太多了,且听我细细道来。
1.ContainerBuilder类:
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<?>>(); 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() { factories.put(Key.newInstance(Container.class, Container.DEFAULT_NAME), CONTAINER_FACTORY); 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) /** * Convenience method. Equivalent to {@code alias(type, Container.DEFAULT_NAME, type)}. */ public <T> ContainerBuilder alias(Class<T> type, String alias) /** * Maps a constant value to the given name. */ public ContainerBuilder constant(String name, String value) { return constant(String.class, name, value); } /** * Upon creation, the {@link Container} will inject static fields and methods * into the given classes. */ public ContainerBuilder injectStatics(Class<?>... types) { staticInjections.addAll(Arrays.asList(types)); return this; } public Container create(boolean loadSingletons) }
先说方法,factory()和alias()有多个重载方法,用于收集创建Container对象的参数,也就是在ContainerProvider的register()中调用factory()方法了。然后调用这里的create()创建出一个Container来。重点要说一下的是,这里所用到的建造者模式。
因为Container对象的创建需要读取多个配置文件的配置信息,然后才能创建出可用的对象,如果直接new的话,创建出来的对象是不可用的。所以这里巧妙地使用了建造者模式来创建Container对象,零散的收集工作分布于各个ContainerProvider的register()中,只要一一调用register()就可以开始创建Container了。更多的关于建造者模式的介绍可以参阅原型模式与创建者模型。
接下来要说的自然就是它的属性了。之前说过,Configuration类的Container属性将容器配置元素对象化了,而这些配置信息还是要暂时保存起来的,那么ContainerProvider类加载进来的配置信息保存在哪里呢?既然是通过ContainerBuilder类的factory()方法收集起来,自然也是保存在ContainerBuilder了。上面代码列出的factories属性和singletonFactories属性都是保存配置信息的。可以看到,factories是一个从Key到InternalFactory的Map,而singletonFactories则是一个保存InternalFactory的List。
接下来看看Key和InternalFactory为何物吧。
class Key<T> { final Class<T> type; final String name; final int hashCode; private Key(Class<T> type, String name) { if (type == null) { throw new NullPointerException("Type is null."); } if (name == null) { throw new NullPointerException("Name is null."); } this.type = type; this.name = name; hashCode = type.hashCode() * 31 + name.hashCode(); } Class<T> getType() { return type; } String getName() { return name; } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object o) { if (!(o instanceof Key)) { return false; } if (o == this) { return true; } Key other = (Key) o; return name.equals(other.name) && type.equals(other.type); } @Override public String toString() { return "[type=" + type.getName() + ", name='" + name + "']"; } static <T> Key<T> newInstance(Class<T> type, String name) { return new Key<T>(type, name); } }
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="struts" class="org.apache.struts2.factory.StrutsResultFactory" />
好,看看InternalFactory,它被设计为接口:
interface InternalFactory<T> extends Serializable { /** * Creates an object to be injected. * * @param context of this injection * @return instance to be injected */ T create(InternalContext context); }
<bean type="com.opensymphony.xwork2.FileManager" class="com.opensymphony.xwork2.util.fs.DefaultFileManager" name="system" scope="singleton"/>
最后看看ContainerBuilder类的构造方法,可以看到加了两个内置的bean,它们并不是配置文件中定义的,而是以编码的方式加入的。这是两个什么样的bean呢?望文生义吧。
2.DefaultConfiguration类的createBootstrapContainer()
看看它的实现:
protected Container createBootstrapContainer(List<ContainerProvider> providers) { ContainerBuilder builder = new ContainerBuilder(); boolean fmFactoryRegistered = false; for (ContainerProvider provider : providers) { if (provider instanceof FileManagerProvider) { provider.register(builder, null); } if (provider instanceof FileManagerFactoryProvider) { provider.register(builder, null); fmFactoryRegistered = true; } } builder.factory(ObjectFactory.class, Scope.SINGLETON); builder.factory(FileManager.class, "system", DefaultFileManager.class, Scope.SINGLETON); if (!fmFactoryRegistered) { builder.factory(FileManagerFactory.class, DefaultFileManagerFactory.class, Scope.SINGLETON); } builder.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON); builder.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON); builder.factory(XWorkConverter.class, Scope.SINGLETON); builder.factory(ConversionPropertiesProcessor.class, DefaultConversionPropertiesProcessor.class, Scope.SINGLETON); builder.factory(ConversionFileProcessor.class, DefaultConversionFileProcessor.class, Scope.SINGLETON); builder.factory(ConversionAnnotationProcessor.class, DefaultConversionAnnotationProcessor.class, Scope.SINGLETON); builder.factory(TypeConverterCreator.class, DefaultTypeConverterCreator.class, Scope.SINGLETON); builder.factory(TypeConverterHolder.class, DefaultTypeConverterHolder.class, Scope.SINGLETON); builder.factory(XWorkBasicConverter.class, Scope.SINGLETON); builder.factory(TypeConverter.class, XWorkConstants.COLLECTION_CONVERTER, CollectionConverter.class, Scope.SINGLETON); builder.factory(TypeConverter.class, XWorkConstants.ARRAY_CONVERTER, ArrayConverter.class, Scope.SINGLETON); builder.factory(TypeConverter.class, XWorkConstants.DATE_CONVERTER, DateConverter.class, Scope.SINGLETON); builder.factory(TypeConverter.class, XWorkConstants.NUMBER_CONVERTER, NumberConverter.class, Scope.SINGLETON); builder.factory(TypeConverter.class, XWorkConstants.STRING_CONVERTER, StringConverter.class, Scope.SINGLETON); builder.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON); builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON); builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON); builder.factory(OgnlUtil.class, Scope.SINGLETON); builder.constant(XWorkConstants.DEV_MODE, "false"); builder.constant(XWorkConstants.LOG_MISSING_PROPERTIES, "false"); builder.constant(XWorkConstants.ENABLE_OGNL_EVAL_EXPRESSION, "false"); builder.constant(XWorkConstants.RELOAD_XML_CONFIGURATION, "false"); return builder.create(true); }
我们只看FileManagerProvider的register()方法实现即可。其他Provider的register()类似。
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException { builder.factory(FileManager.class, name, fileManagerClass, Scope.SINGLETON); }
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); } @Override 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); }
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; }
为什么要加入这么多的factory呢?后面说到Container的inject()就知道啦!
ok,收集完了配置信息,就可以调用create()创建出Container了。
3.ContainerBuilder的create():
欲知详情,且听下回分解。
struts2源码学习之初始化(三),布布扣,bubuko.com
标签:struts2 struts2初始化 容器 container containerbuilder
原文地址:http://blog.csdn.net/a1969212650/article/details/34846899