在init初始化方法中我们看到这样一句
InitOperations init = new InitOperations();
这个类没什么作用,就是一个辅助类,来完成初始化的操作。
继续往下看
FilterHostConfig config = new FilterHostConfig(filterConfig);
init.initLogging(config);
Dispatcher dispatcher = init.initDispatcher(config);
init.initStaticContentLoader(config, dispatcher);
创建了FilterHostConfig,这个类也没什么作用就是包装FilterConfig
用官方的原话说
Host configuration that wraps FilterConfig
通过传入一个filterConfig完成该类的初始化。
public class FilterHostConfig implements HostConfig {
private FilterConfig config;
public FilterHostConfig(FilterConfig config) {
this.config = config;
}
public String getInitParameter(String key) {
return config.getInitParameter(key);
}
public Iterator<String> getInitParameterNames() {
return MakeIterator.convert(config.getInitParameterNames());
}
public ServletContext getServletContext() {
return config.getServletContext();
}
}
该类处理完成,真正的初始化才开始,通过初始化辅助类InitOperations来完成初始化。
首先初始化日志信息
init.initLogging(config);
public void initLogging( HostConfig filterConfig ) {
String factoryName = filterConfig.getInitParameter("loggerFactory");
if (factoryName != null) {
try {
Class cls = ClassLoaderUtil.loadClass(factoryName, this.getClass());
LoggerFactory fac = (LoggerFactory) cls.newInstance();
LoggerFactory.setLoggerFactory(fac);
} catch ( InstantiationException e ) {
System.err.println("Unable to instantiate logger factory: " + factoryName + ", using default");
e.printStackTrace();
} catch ( IllegalAccessException e ) {
System.err.println("Unable to access logger factory: " + factoryName + ", using default");
e.printStackTrace();
} catch ( ClassNotFoundException e ) {
System.err.println("Unable to locate logger factory class: " + factoryName + ", using default");
e.printStackTrace();
}
}
}
通过代码我们可以清晰的看到factoryName一定是空的,因为我们压根就没在web.xml中配置factoryName.
所以里面的方法一定不执行。
直接返回。
接下来进入到Dispatcher dispatcher = init.initDispatcher(config);
初始化并创建Dispatcher
Dispatcher是struts2的核心类,完成大部分任务调度,所有的请求共享这一实例。
public Dispatcher initDispatcher( HostConfig filterConfig ) {
Dispatcher dispatcher = createDispatcher(filterConfig);
dispatcher.init();
return dispatcher;
}
通过代码也可以看到Dispatcher是先创建,然后初始化。
它的创建很简单
private Dispatcher createDispatcher( HostConfig filterConfig ) {
Map<String, String> params = new HashMap<String, String>();
for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
String name = (String) e.next();
String value = filterConfig.getInitParameter(name);
params.put(name, value);
}
return new Dispatcher(filterConfig.getServletContext(), params);
}
把web.xml 中所有的配置信息取出来,放入一个hashmap中,然后存入Dispatcher中。就这样,完了
然后进入初始化,这个有点点复杂
public void init() {
if (configurationManager == null) {
configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
}
try {
init_DefaultProperties(); // [1]
init_TraditionalXmlConfigurations(); // [2]
init_LegacyStrutsProperties(); // [3]
init_CustomConfigurationProviders(); // [5]
init_FilterInitParameters() ; // [6]
init_AliasStandardObjects() ; // [7]
Container container = init_PreloadConfiguration();
container.inject(this);
init_CheckConfigurationReloading(container);
init_CheckWebLogicWorkaround(container);
if (!dispatcherListeners.isEmpty()) {
for (DispatcherListener l : dispatcherListeners) {
l.dispatcherInitialized(this);
}
}
} catch (Exception ex) {
if (LOG.isErrorEnabled())
LOG.error("Dispatcher initialization failed", ex);
throw new StrutsException(ex);
}
}
通过代码可以看到,初始化做了很多事,首先是创建configurationManager
protected ConfigurationManager createConfigurationManager(String name) {
return new ConfigurationManager(name);
}
直接new一个configurationManager出来。默认的名称就是struts
初始化属性读取的类
private void init_DefaultProperties() {
configurationManager.addContainerProvider(new DefaultPropertiesProvider());
}
以下所有的都一样,将所有的provider初始化,所有的Provider实现类都实现了ConfigurationProvider这个接口。
ConfigurationProvider这个接口又干嘛呢?
public interface ConfigurationProvider extends ContainerProvider, PackageProvider {
}
通过代码可以看到核心不在这里,在ContainerProvider和PackageProvider,
这里需要说的是ContainerProvider是容器的初始化,PackageProvider是包的初始化.
什么是容器呢?在struts2中constants/properties配置的信息就是容器的相关信息
PackageProvider就是包的信息,比如我们的struts.xml
回到初始化代码中,DefaultPropertiesProvider就是提供了一个读取默认的struts.properties的实现类。
好了,继续初始化操作。
初始化init_TraditionalXmlConfigurations
private void init_TraditionalXmlConfigurations() {
String configPaths = initParams.get("config");
if (configPaths == null) {
configPaths = DEFAULT_CONFIGURATION_PATHS;
}
String[] files = configPaths.split("\\s*[,]\\s*");
for (String file : files) {
if (file.endsWith(".xml")) {
if ("xwork.xml".equals(file)) {
configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false));
} else {
configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
}
} else {
throw new IllegalArgumentException("Invalid configuration file name");
}
}
}
这里提供了俩种初始化配置文件的方法,当然他也提供了选择String configPaths = initParams.get("config");
但是我们在web.xml中没配置,所有默认的一定是struts,而不是xwork
protected XmlConfigurationProvider createStrutsXmlConfigurationProvider(String filename, boolean errorIfMissing, ServletContext ctx) {
return new StrutsXmlConfigurationProvider(filename, errorIfMissing, ctx);
}
configPaths = DEFAULT_CONFIGURATION_PATHS;
这里我们可以得到证明
private static final String DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml";
继续往里面看,我们看到
public StrutsXmlConfigurationProvider(String filename, boolean errorIfMissing, ServletContext ctx) {
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");
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.3//EN", "struts-2.3.dtd");
setDtdMappings(dtdMappings);
File file = new File(filename);
if (file.getParent() != null) {
this.baseDir = file.getParentFile();
}
}
加入了struts配置文件的验证dtd,在后续会讲
完成了struts配置文件的初始化,继续初始化
init_LegacyStrutsProperties
private void init_LegacyStrutsProperties() {
configurationManager.addContainerProvider(new LegacyPropertiesConfigurationProvider());
}
LegacyPropertiesConfigurationProvider这个初始化又干嘛呢?这个初始化主要完成除去上面初始化剩下的其他配置信息想初始化。
init_CustomConfigurationProviders();这个初始化很关键
以上的初始化都说初始化struts框架的配置信息,而这个初始化就是初始化我们在开发中写的配置文件
private void init_CustomConfigurationProviders() {
String configProvs = initParams.get("configProviders");
if (configProvs != null) {
String[] classes = configProvs.split("\\s*[,]\\s*");
for (String cname : classes) {
try {
Class cls = ClassLoaderUtil.loadClass(cname, this.getClass());
ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();
configurationManager.addContainerProvider(prov);
} catch (InstantiationException e) {
throw new ConfigurationException("Unable to instantiate provider: "+cname, e);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Unable to access provider: "+cname, e);
} catch (ClassNotFoundException e) {
throw new ConfigurationException("Unable to locate provider class: "+cname, e);
}
}
}
}
通过代码可以看到,通过类加载器加载上来,然后放入configurationManager中。
private void init_AliasStandardObjects() {
configurationManager.addContainerProvider(new BeanSelectionProvider());
}
这个初始化是初始化扩展框架的插件信息。
然后初始化一个容器
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);
return container;
}
struts2的容器用来实现依赖注入和控制反转,定义如下
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
*/
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();
}
未完待续