Struts2 源码初步学习—Dispatcher初始化细节
先贴代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
这些小的初始化方法
都会用到ConfigurationManager这个类的对象。这个类是xwork的配置管理类。
这个类中涉及两个基础知识ReentrantLock 和 CopyOnWriteArrayList类,详细说明参见JDK
并注意ReentrantLock基本用法 参见方法 public List<ContainerProvider> getContainerProviders()
在方法一开始出lock上,在方法的最后finally部分unlock
看下方法体
providerLock.lock();
try {
if (containerProviders.size() == 0) {
containerProviders.add(new XWorkConfigurationProvider());
containerProviders.add(new XmlConfigurationProvider("xwork.xml", false));
}
returncontainerProviders;
} finally {
providerLock.unlock();
}
同时这个类中会主要涉及ContainerProvider这个类
上面是ContainerProvider接口的实现结构
可以看出struts(xwork)几乎未每种配置做了provider
看下这个接口定义的方法如下:
这个接口主要要实现register方法,其中有个参数是ContainerBuilder,这个接口是ContainerProvider,都跟Container有关,别着急,我后面会专门写一篇介绍struts容器的。当然我们在这边关心的不是其register方法,而是init方法,毕竟这篇文章是分析的Dispatcher的init细节
这个ConfigurationManager类有个addContainerProvider方法,主要是用来维护属性
private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<ContainerProvider>();
每当调用一个不同的init方法时,便会用几乎不同的ContainerProvider,so这个属性就是用来持有这些provider的列表
不难发现对于类Dispatcher来说是在init方法一开始处初始化
if (configurationManager == null) {
configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
}
下面逐一分析那几个init方法
init_DefaultProperties 方法很简单 就是把DefaultPropertiesProvider加进上面所说的类ConfigurationManager的containerProviders (是个列表)属性,当然从上面的图不难发现DefaultPropertiesProvider实现了ContainerProvider接口
init_TraditionalXmlConfigurations这个方法也简单,
先是从初始化参数中读取有没有配置config这个参数,若没有,default配置文件则用默认的privatestaticfinal String DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml";
然后根据这些文件名字的不同做一些特殊处理
xwork.xml的用XmlConfigurationProvider
其他的用StrutsXmlConfigurationProvide
当然仍然是将这些provider加进上面所说的类ConfigurationManager的containerProviders (是个列表)属性。只是这两个provider的构造方法做了点事情。上面的DefaultPropertiesProvider的构造方法根本没有显式声明
看下StrutsXmlConfigurationProvide的构造方法做了啥?
贴下代码一目明了
super(filename, errorIfMissing);
this.servletContext = ctx;
this.filename = filename;
reloadKey = "configurationReload-"+filename;
Map<String,String> dtdMappings = new HashMap<String,String>(getDtdMappings());
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.0//EN", "struts-2.0.dtd");
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1//EN", "struts-2.1.dtd");
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN", "struts-2.1.7.dtd");
setDtdMappings(dtdMappings);
File file = new File(filename);
if (file.getParent() != null) {
this.baseDir = file.getParentFile();
}
setDtdMappings 是为后面解析这些配置文件做校验用的。
-
init_LegacyStrutsProperties 这个个初始化也没做什么事 对应的provider为LegacyPropertiesConfigurationProvider
-
init_CustomConfigurationProviders 初始化init参数中自定义的(如果有)ConfigurationProvider
-
init_FilterInitParameters 这个初始化方法中ConfigurationManager的containerProviders列表中加入一个内部类 new ConfigurationProvider() {…} 这个provider的init方法没做什么事 register方法倒是做了点事情
-
init_AliasStandardObjects 将beanSelectionProvider 放进了ConfigurationManager的containerProviders列表中
-
init_PreloadConfiguration 初始化容器 这个方法很关键。做了很多事情。包括加载配置文件 包括初始化容器 here --> reloadContainer-->createBootStrap等等。F3跟进去看下,看不出来啥。还要再跟一层,主要是Configuration config = configurationManager.getConfiguration();。
看configurationManager类的getConfiguration()方法
configuration.reloadContainer(getContainerProviders());
分析 reloadContainer方法,传进来的参数就是上面几步初始化一直在维护的containerProviders(provider列表)
reloadContainer方法迭代这个provider列表做了两件事情 就是调用每个provider的init和register方法,其实在ContainerProvider接口中能看到定义了这样的方法
containerProvider.init(this);
containerProvider.register(builder, props); 这个register方法牵扯到的两个参数,ContainerBuilder和ContainerProperties两个类的对象,这两个类的对象都是在这个方法体中直接new出来的。
ContainerProperties props = new ContainerProperties();
ContainerBuilder builder = new ContainerBuilder();
ContainerBuilder 的构造方法中将默认两种必要的工厂加到builder的属性final Map<Key<?>, InternalFactory<?>> factories 中。这两中必要的工厂分别是日志工厂和容器工厂。
这边涉及到接口 InternalFactory 注释为 “ 创建那些将被注入的对象” 。只定义了一个方法
T create(InternalContext context); 就是创建工厂中的产品。
这个下面牵扯到的类就相对多点 写法相对绕点了
<T> InternalFactory<? extends T> scopeFactory(Class<T> type, String name,
InternalFactory<? extends T> factory) {
return factory;
未完待续