在上一篇文章 struts2源码探索之初始化(三)中,已经分析到了创建bootstrap这个容器的最后一步了,调用ContainerBuilder类的create()。恩,接下来看这个方法:
public Container create(boolean loadSingletons) { ensureNotCreated(); created = true; final ContainerImpl container = new ContainerImpl( new HashMap<Key<?>, InternalFactory<?>>(factories)); if (loadSingletons) { container.callInContext(new ContainerImpl.ContextualCallable<Void>() { public Void call(InternalContext context) { for (InternalFactory<?> factory : singletonFactories) { factory.create(context); } return null; } }); } container.injectStatics(staticInjections); return container; }
1.Container
前面已经多次提到了这个接口,但一直没有一探究竟,现在是时候了。看看接口的定义吧:
public interface Container extends Serializable { /** * Default dependency name. */ String DEFAULT_NAME = "default"; /** * Injects dependencies into the fields and methods of an existing object. */ void inject(Object o); /** * Creates and injects a new instance of type {@code implementation}. */ <T> T inject(Class<T> implementation); /** * Gets an instance of the given dependency which was declared in * {@link com.opensymphony.xwork2.inject.ContainerBuilder}. */ <T> T getInstance(Class<T> type, String name); /** * Convenience method. Equivalent to {@code getInstance(type, * DEFAULT_NAME)}. */ <T> T getInstance(Class<T> type); /** * Gets a set of all registered names for the given type * @param type The instance type * @return A set of registered names or empty set if no instances are registered for that type */ Set<String> getInstanceNames(Class<?> type); /** * Sets the scope strategy for the current thread. */ void setScopeStrategy(Scope.Strategy scopeStrategy); /** * Removes the scope strategy for the current thread. */ void removeScopeStrategy(); }
2.ContainerImpl
先看它存储数据的属性:
class ContainerImpl implements Container { final Map<Key<?>, InternalFactory<?>> factories; final Map<Class<?>, Set<String>> factoryNamesByType; /** * Field and method injectors. */ final Map<Class<?>, List<Injector>> injectors = new ReferenceCache<Class<?>, List<Injector>>() { @Override protected List<Injector> create( Class<?> key ) { List<Injector> injectors = new ArrayList<Injector>(); addInjectors(key, injectors); return injectors; } }; }
至此,也就完成了bootstrap这个容器的创建。所以,让我们回到Configuration类。这真是相当漫长的旅途啊。
希望大家还记得我们曾经走过的这段路:
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; }
调用各个Provider的register()
下面就说说各个Provider的register()
1.FileManagerProvider
这个前面说过了,就不说了。
2.DefaultPropertiesProvider
加载default.properties文件的配置信息到ContainerProperties对象中。
3.XmlConfigurationProvider
加载xml配置文件(struts-default.xml,struts.xml,)中的<bean>和<constant>元素,bean就加入到factories,constant就加入到ContainerProperties,这些信息最终都由Container对象去维护。
4.LegacyPropertiesConfigurationProvider
加载properties文件,并且加入一个创建Local的InternalFactory。
5.FilterInitParameters的匿名Provider
加入filter的参数到ContainerProperties
6.BeanSelectionProvider
加入许多的bean factory和常量
public void register(ContainerBuilder builder, LocatableProperties props) { alias(ObjectFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY, builder, props); alias(FileManagerFactory.class, StrutsConstants.STRUTS_FILE_MANAGER_FACTORY, builder, props, Scope.SINGLETON); alias(XWorkConverter.class, StrutsConstants.STRUTS_XWORKCONVERTER, builder, props); alias(CollectionConverter.class, StrutsConstants.STRUTS_CONVERTER_COLLECTION, builder, props); alias(ArrayConverter.class, StrutsConstants.STRUTS_CONVERTER_ARRAY, builder, props); alias(DateConverter.class, StrutsConstants.STRUTS_CONVERTER_DATE, builder, props); alias(NumberConverter.class, StrutsConstants.STRUTS_CONVERTER_NUMBER, builder, props); alias(StringConverter.class, StrutsConstants.STRUTS_CONVERTER_STRING, builder, props); alias(ConversionPropertiesProcessor.class, StrutsConstants.STRUTS_CONVERTER_PROPERTIES_PROCESSOR, builder, props); alias(ConversionFileProcessor.class, StrutsConstants.STRUTS_CONVERTER_FILE_PROCESSOR, builder, props); alias(ConversionAnnotationProcessor.class, StrutsConstants.STRUTS_CONVERTER_ANNOTATION_PROCESSOR, builder, props); alias(TypeConverterCreator.class, StrutsConstants.STRUTS_CONVERTER_CREATOR, builder, props); alias(TypeConverterHolder.class, StrutsConstants.STRUTS_CONVERTER_HOLDER, builder, props); alias(TextProvider.class, StrutsConstants.STRUTS_XWORKTEXTPROVIDER, builder, props, Scope.DEFAULT); alias(LocaleProvider.class, StrutsConstants.STRUTS_LOCALE_PROVIDER, builder, props); alias(ActionProxyFactory.class, StrutsConstants.STRUTS_ACTIONPROXYFACTORY, builder, props); alias(ObjectTypeDeterminer.class, StrutsConstants.STRUTS_OBJECTTYPEDETERMINER, builder, props); alias(ActionMapper.class, StrutsConstants.STRUTS_MAPPER_CLASS, builder, props); alias(MultiPartRequest.class, StrutsConstants.STRUTS_MULTIPART_PARSER, builder, props, Scope.DEFAULT); alias(FreemarkerManager.class, StrutsConstants.STRUTS_FREEMARKER_MANAGER_CLASSNAME, builder, props); alias(VelocityManager.class, StrutsConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME, builder, props); alias(UrlRenderer.class, StrutsConstants.STRUTS_URL_RENDERER, builder, props); alias(ActionValidatorManager.class, StrutsConstants.STRUTS_ACTIONVALIDATORMANAGER, builder, props); alias(ValueStackFactory.class, StrutsConstants.STRUTS_VALUESTACKFACTORY, builder, props); alias(ReflectionProvider.class, StrutsConstants.STRUTS_REFLECTIONPROVIDER, builder, props); alias(ReflectionContextFactory.class, StrutsConstants.STRUTS_REFLECTIONCONTEXTFACTORY, builder, props); alias(PatternMatcher.class, StrutsConstants.STRUTS_PATTERNMATCHER, builder, props); alias(StaticContentLoader.class, StrutsConstants.STRUTS_STATIC_CONTENT_LOADER, builder, props); alias(UnknownHandlerManager.class, StrutsConstants.STRUTS_UNKNOWN_HANDLER_MANAGER, builder, props); alias(UrlHelper.class, StrutsConstants.STRUTS_URL_HELPER, builder, props); alias(TextParser.class, StrutsConstants.STRUTS_EXPRESSION_PARSER, builder, props); if ("true".equalsIgnoreCase(props.getProperty(StrutsConstants.STRUTS_DEVMODE))) { props.setProperty(StrutsConstants.STRUTS_I18N_RELOAD, "true"); props.setProperty(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, "true"); props.setProperty(StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE, "false"); props.setProperty(StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE_UPDATE_DELAY, "0"); // Convert struts properties into ones that xwork expects props.setProperty(XWorkConstants.DEV_MODE, "true"); } else { props.setProperty(XWorkConstants.DEV_MODE, "false"); } // Convert Struts properties into XWork properties convertIfExist(props, StrutsConstants.STRUTS_LOG_MISSING_PROPERTIES, XWorkConstants.LOG_MISSING_PROPERTIES); convertIfExist(props, StrutsConstants.STRUTS_ENABLE_OGNL_EXPRESSION_CACHE, XWorkConstants.ENABLE_OGNL_EXPRESSION_CACHE); convertIfExist(props, StrutsConstants.STRUTS_ENABLE_OGNL_EVAL_EXPRESSION, XWorkConstants.ENABLE_OGNL_EVAL_EXPRESSION); convertIfExist(props, StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, XWorkConstants.ALLOW_STATIC_METHOD_ACCESS); convertIfExist(props, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, XWorkConstants.RELOAD_XML_CONFIGURATION); LocalizedTextUtil.addDefaultResourceBundle("org/apache/struts2/struts-messages"); loadCustomResourceBundles(props); }
Configuration Factory
各个Provider的register()方法加入了许多的factory,另外还加了创建Configuration的factory。
factory的收集完成之后,就是创建Container了,和上一个Container即bootstrap的创建过程是一样的,就不重复说了。
接着看reloadContainer(),已经到了这段代码:
container = builder.create(false); setContext(container);
先看接下来的代码:
for (final ContainerProvider containerProvider : providers) { if (containerProvider instanceof PackageProvider) { container.inject(containerProvider); ((PackageProvider)containerProvider).loadPackages(); packageProviders.add((PackageProvider)containerProvider); } }
public void loadPackages() throws ConfigurationException { List<Element> reloads = new ArrayList<Element>(); verifyPackageStructure(); for (Document doc : documents) { Element rootElement = doc.getDocumentElement(); NodeList children = rootElement.getChildNodes(); int childSize = children.getLength(); for (int i = 0; i < childSize; i++) { Node childNode = children.item(i); if (childNode instanceof Element) { Element child = (Element) childNode; final String nodeName = child.getNodeName(); if ("package".equals(nodeName)) { PackageConfig cfg = addPackage(child); if (cfg.isNeedsRefresh()) { reloads.add(child); } } } } loadExtraConfiguration(doc); } if (reloads.size() > 0) { reloadRequiredPackages(reloads); } for (Document doc : documents) { loadExtraConfiguration(doc); } documents.clear(); declaredPackages.clear(); configuration = null; }
接下来是这段代码:
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();
public class PackageConfig extends Located implements Comparable, Serializable, InterceptorLocator { private static final Logger LOG = LoggerFactory.getLogger(PackageConfig.class); protected Map<String, ActionConfig> actionConfigs; protected Map<String, ResultConfig> globalResultConfigs; protected Map<String, Object> interceptorConfigs; protected Map<String, ResultTypeConfig> resultTypeConfigs; protected List<ExceptionMappingConfig> globalExceptionMappingConfigs; protected List<PackageConfig> parents; protected String defaultInterceptorRef; protected String defaultActionRef; protected String defaultResultType; protected String defaultClassRef; protected String name; protected String namespace = ""; protected boolean isAbstract = false; protected boolean needsRefresh; }
到此为止,最终的Container也构造出来了。
接下来干嘛呢?接下来又回到了Dispatcher的init()方法。想当初,我们是从以下这个方法开始渐行渐远的:
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; }
看ContainerHolder类的源代码:
class ContainerHolder { private static ThreadLocal<Container> instance = new ThreadLocal<Container>(); public static void store(Container instance) { boolean reloadConfigs = Boolean.valueOf(instance.getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD)); if (!reloadConfigs) { // reloadConfigs is false, configuration will do not change, just keep it ContainerHolder.instance.set(instance); } } public static Container get() { return ContainerHolder.instance.get(); } public static void clear() { ContainerHolder.instance.remove(); } }
接下来就看前面提到的注入了。看Dispatcher类的init()中,这么一句代码:
container.inject(this);
/** * Modify state of StrutsConstants.STRUTS_DEVMODE setting. * @param mode New setting */ @Inject(StrutsConstants.STRUTS_DEVMODE) public void setDevMode(String mode) { devMode = "true".equals(mode); } /** * Modify state of StrutsConstants.DISABLE_REQUEST_ATTRIBUTE_VALUE_STACK_LOOKUP setting. * @param disableRequestAttributeValueStackLookup New setting */ @Inject(value=StrutsConstants.STRUTS_DISABLE_REQUEST_ATTRIBUTE_VALUE_STACK_LOOKUP, required=false) public void setDisableRequestAttributeValueStackLookup(String disableRequestAttributeValueStackLookup) { this.disableRequestAttributeValueStackLookup = "true".equalsIgnoreCase(disableRequestAttributeValueStackLookup); } /** * Modify state of StrutsConstants.STRUTS_LOCALE setting. * @param val New setting */ @Inject(value=StrutsConstants.STRUTS_LOCALE, required=false) public void setDefaultLocale(String val) { defaultLocale = val; } /** * Modify state of StrutsConstants.STRUTS_I18N_ENCODING setting. * @param val New setting */ @Inject(StrutsConstants.STRUTS_I18N_ENCODING) public void setDefaultEncoding(String val) { defaultEncoding = val; } /** * Modify state of StrutsConstants.STRUTS_MULTIPART_SAVEDIR setting. * @param val New setting */ @Inject(StrutsConstants.STRUTS_MULTIPART_SAVEDIR) public void setMultipartSaveDir(String val) { multipartSaveDir = val; } @Inject(StrutsConstants.STRUTS_MULTIPART_PARSER) public void setMultipartHandler(String val) { multipartHandlerName = val; } @Inject public void setValueStackFactory(ValueStackFactory valueStackFactory) { this.valueStackFactory = valueStackFactory; } @Inject(StrutsConstants.STRUTS_HANDLE_EXCEPTION) public void setHandleException(String handleException) { this.handleException = Boolean.parseBoolean(handleException); }
通俗易懂的说,对于带这种注解的方法来说,当调用container.inject(dispatcher)方法时,以上方法会一一被调用,并且传递进去的参数就是Container中内置的bean或者常量。是不是相当神奇呢?
通过这种方法,Container中的bean就可以为任何类服务了。
ok,到此为止,Dispatcher的初始化也已经全部完成。这就意味着,本系列的文章到此就要告一段落了。
struts2框架的初始化写了四篇文章才算基本介绍完成,嘿嘿,有小小的成就感,毕竟,如此遥远的旅途啊。
虽然才刚刚起步,但是,还是会再接再厉,接下来就是struts2处理请求的过程了。这就比初始化还要复杂的多了,真是一个挑战呢。
struts2源码探索之初始化(四),布布扣,bubuko.com
原文:http://blog.csdn.net/a1969212650/article/details/35548323