在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(); }
未完待续