Struts2的配置文件读取(一)
struts2利用FilterDispatcher来拦截请求,然后进行请求的分发,在FilterDispatcher的#init()方法里,实现了配置文件的读入。
代码如下:
-------------------------------------------------------------------------------------------------
先调用#createDispatcher()来创建一个Dispatcher对象,并将FilterConfig中的属性读出,代码如下:
在#createDispatcher()中,将Filter的配置中的所有属性都写入一个HashMap并作为参数传递给Dispatcher的构造函数。
-------------------------------------------------------------------------------------------------
再回到#init()函数中,创建完Dispatcher对象后,紧接着调用Dispatcher的#init()方法。代码如下:
首先实例化一个ConfigurationManager对象。
然后就是调用一系列的#init_*()方法了。
-------------------------------------------------------------------------------------------------
●第一个是
这个方法中是将一个DefaultPropertiesProvider对象追加到ConfigurationManager对象内部的ConfigurationProvider队列中。
DefaultPropertiesProvider的#register()方法可以载入org/apache/struts2/default.properties中定义的属性。
-------------------------------------------------------------------------------------------------
●第二个是
这里负责载入的是FilterDispatcher的配置中所定义的config属性。
如果用户没有定义config属性,struts默认会载入DEFAULT_CONFIGURATION_PATHS这个值所代表的xml文件。
它的值为"struts-default.xml,struts-plugin.xml,struts.xml"。也就是说框架默认会载入这三个项目xml文件。
下一步框架会逐个判断每个config属性中定义的文件。如果文件名为"xwork.xml",框架会用XmlConfigurationProvider类去处理,反之则用StrutsXmlConfigurationProvider类去处理。
-------------------------------------------------------------------------------------------------
●第三个是
向ConfigurationManager加入了一个LegacyPropertiesConfigurationProvider。
-------------------------------------------------------------------------------------------------
●第四个是
这次处理的是FilterDispatcher的配置中所定义的actionPackages属性。传说中的Struts 2 零配置。
该参数的值是一个以英文逗号(,)隔开的字符串,每个字符串都是一个包空间,Struts 2框架将扫描这些包空间下的Action类。
-------------------------------------------------------------------------------------------------
●第五个是
此方法处理的是FilterDispatcher的配置中所定义的configProviders属性。负责载入用户自定义的ConfigurationProvider。
-------------------------------------------------------------------------------------------------
●第六个是
此方法用来处理FilterDispatcher的配置中所定义的所有属性。
-------------------------------------------------------------------------------------------------
●第七个是
-------------------------------------------------------------------------------------------------
执行完七个init_*方法后,Dispatcher的#init()会接着调用#init_PreloadConfiguration(),构建一个用于依赖注射的Container对象。
此方法首先获取到ConfigurationManager中的Configuration对象,在#getConfiguration()内部,调用上边6步添加到ConfigurationManager的ConfigurationProviders的#register()方法。
其中的重点就是DefaultConfiguration的#reload()方法。
代码如下:
- public void init(FilterConfig filterConfig) throws ServletException {
- this.filterConfig = filterConfig;
- dispatcher = createDispatcher(filterConfig);
- dispatcher.init();
- String param = filterConfig.getInitParameter("packages");
- String packages = "org.apache.struts2.static template org.apache.struts2.interceptor.debugging";
- if (param != null) {
- packages = param + " " + packages;
- }
- this.pathPrefixes = parse(packages);
- }
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
dispatcher = createDispatcher(filterConfig);
dispatcher.init();
String param = filterConfig.getInitParameter("packages");
String packages = "org.apache.struts2.static template org.apache.struts2.interceptor.debugging";
if (param != null) {
packages = param + " " + packages;
}
this.pathPrefixes = parse(packages);
}
-------------------------------------------------------------------------------------------------
先调用#createDispatcher()来创建一个Dispatcher对象,并将FilterConfig中的属性读出,代码如下:
- protected Dispatcher createDispatcher(FilterConfig filterConfig) {
- Map params = new HashMap();
- for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {
- String name = (String) e.nextElement();
- String value = filterConfig.getInitParameter(name);
- params.put(name, value);
- }
- return new Dispatcher(filterConfig.getServletContext(), params);
- }
protected Dispatcher createDispatcher(FilterConfig filterConfig) {
Map params = new HashMap();
for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {
String name = (String) e.nextElement();
String value = filterConfig.getInitParameter(name);
params.put(name, value);
}
return new Dispatcher(filterConfig.getServletContext(), params);
}
在#createDispatcher()中,将Filter的配置中的所有属性都写入一个HashMap并作为参数传递给Dispatcher的构造函数。
-------------------------------------------------------------------------------------------------
再回到#init()函数中,创建完Dispatcher对象后,紧接着调用Dispatcher的#init()方法。代码如下:
- public void init() {
- if (configurationManager == null) {
- configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
- }
- init_DefaultProperties(); // [1]
- init_TraditionalXmlConfigurations(); // [2]
- init_LegacyStrutsProperties(); // [3]
- init_ZeroConfiguration(); // [4]
- init_CustomConfigurationProviders(); // [5]
- init_MethodConfigurationProvider();
- init_FilterInitParameters(); // [6]
- init_AliasStandardObjects(); // [7]
- Container container = init_PreloadConfiguration();
- init_CheckConfigurationReloading(container);
- init_CheckWebLogicWorkaround(container);
- }
public void init() {
if (configurationManager == null) {
configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
}
init_DefaultProperties(); // [1]
init_TraditionalXmlConfigurations(); // [2]
init_LegacyStrutsProperties(); // [3]
init_ZeroConfiguration(); // [4]
init_CustomConfigurationProviders(); // [5]
init_MethodConfigurationProvider();
init_FilterInitParameters(); // [6]
init_AliasStandardObjects(); // [7]
Container container = init_PreloadConfiguration();
init_CheckConfigurationReloading(container);
init_CheckWebLogicWorkaround(container);
}
首先实例化一个ConfigurationManager对象。
然后就是调用一系列的#init_*()方法了。
-------------------------------------------------------------------------------------------------
●第一个是
- private void init_DefaultProperties() {
- configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());
- }
private void init_DefaultProperties() {
configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());
}
这个方法中是将一个DefaultPropertiesProvider对象追加到ConfigurationManager对象内部的ConfigurationProvider队列中。
DefaultPropertiesProvider的#register()方法可以载入org/apache/struts2/default.properties中定义的属性。
-------------------------------------------------------------------------------------------------
●第二个是
- private void init_TraditionalXmlConfigurations() {
- String configPaths = initParams.get("config");
- if (configPaths == null) {
- configPaths = DEFAULT_CONFIGURATION_PATHS;
- }
- String[] files = configPaths.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");
- for (String file : files) {
- if (file.endsWith(".xml")) {
- if ("xwork.xml".equals(file)) {
- configurationManager.addConfigurationProvider(new XmlConfigurationProvider(
- file, false));
- } else {
- configurationManager
- .addConfigurationProvider(new StrutsXmlConfigurationProvider(file,
- false, servletContext));
- }
- } else {
- throw new IllegalArgumentException("Invalid configuration file name");
- }
- }
- }
private void init_TraditionalXmlConfigurations() {
String configPaths = initParams.get("config");
if (configPaths == null) {
configPaths = DEFAULT_CONFIGURATION_PATHS;
}
String[] files = configPaths.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");
for (String file : files) {
if (file.endsWith(".xml")) {
if ("xwork.xml".equals(file)) {
configurationManager.addConfigurationProvider(new XmlConfigurationProvider(
file, false));
} else {
configurationManager
.addConfigurationProvider(new StrutsXmlConfigurationProvider(file,
false, servletContext));
}
} else {
throw new IllegalArgumentException("Invalid configuration file name");
}
}
}
这里负责载入的是FilterDispatcher的配置中所定义的config属性。
如果用户没有定义config属性,struts默认会载入DEFAULT_CONFIGURATION_PATHS这个值所代表的xml文件。
它的值为"struts-default.xml,struts-plugin.xml,struts.xml"。也就是说框架默认会载入这三个项目xml文件。
下一步框架会逐个判断每个config属性中定义的文件。如果文件名为"xwork.xml",框架会用XmlConfigurationProvider类去处理,反之则用StrutsXmlConfigurationProvider类去处理。
-------------------------------------------------------------------------------------------------
●第三个是
- private void init_LegacyStrutsProperties() {
- configurationManager.addConfigurationProvider(new LegacyPropertiesConfigurationProvider());
- }
private void init_LegacyStrutsProperties() {
configurationManager.addConfigurationProvider(new LegacyPropertiesConfigurationProvider());
}
向ConfigurationManager加入了一个LegacyPropertiesConfigurationProvider。
-------------------------------------------------------------------------------------------------
●第四个是
- private void init_ZeroConfiguration() {
- String packages = initParams.get("actionPackages");
- if (packages != null) {
- String[] names = packages.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");
- // Initialize the classloader scanner with the configured packages
- if (names.length > 0) {
- ClasspathConfigurationProvider provider = new ClasspathConfigurationProvider(names);
- provider.setPageLocator(new ServletContextPageLocator(servletContext));
- configurationManager.addConfigurationProvider(provider);
- }
- }
- }
private void init_ZeroConfiguration() {
String packages = initParams.get("actionPackages");
if (packages != null) {
String[] names = packages.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");
// Initialize the classloader scanner with the configured packages
if (names.length > 0) {
ClasspathConfigurationProvider provider = new ClasspathConfigurationProvider(names);
provider.setPageLocator(new ServletContextPageLocator(servletContext));
configurationManager.addConfigurationProvider(provider);
}
}
}
这次处理的是FilterDispatcher的配置中所定义的actionPackages属性。传说中的Struts 2 零配置。
该参数的值是一个以英文逗号(,)隔开的字符串,每个字符串都是一个包空间,Struts 2框架将扫描这些包空间下的Action类。
-------------------------------------------------------------------------------------------------
●第五个是
- private void init_CustomConfigurationProviders() {
- String configProvs = initParams.get("configProviders");
- if (configProvs != null) {
- String[] classes = configProvs.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");
- for (String cname : classes) {
- try {
- Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());
- ConfigurationProvider prov = (ConfigurationProvider) cls.newInstance();
- configurationManager.addConfigurationProvider(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);
- }
- }
- }
- }
private void init_CustomConfigurationProviders() {
String configProvs = initParams.get("configProviders");
if (configProvs != null) {
String[] classes = configProvs.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");
for (String cname : classes) {
try {
Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());
ConfigurationProvider prov = (ConfigurationProvider) cls.newInstance();
configurationManager.addConfigurationProvider(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);
}
}
}
}
此方法处理的是FilterDispatcher的配置中所定义的configProviders属性。负责载入用户自定义的ConfigurationProvider。
-------------------------------------------------------------------------------------------------
●第六个是
- private void init_FilterInitParameters() {
- configurationManager.addConfigurationProvider(new ConfigurationProvider() {
- public void destroy() {
- }
- public void init(Configuration configuration) throws ConfigurationException {
- }
- public void loadPackages() throws ConfigurationException {
- }
- public boolean needsReload() {
- return false;
- }
- public void register(ContainerBuilder builder, LocatableProperties props)
- throws ConfigurationException {
- props.putAll(initParams);
- }
- });
- }
private void init_FilterInitParameters() {
configurationManager.addConfigurationProvider(new ConfigurationProvider() {
public void destroy() {
}
public void init(Configuration configuration) throws ConfigurationException {
}
public void loadPackages() throws ConfigurationException {
}
public boolean needsReload() {
return false;
}
public void register(ContainerBuilder builder, LocatableProperties props)
throws ConfigurationException {
props.putAll(initParams);
}
});
}
此方法用来处理FilterDispatcher的配置中所定义的所有属性。
-------------------------------------------------------------------------------------------------
●第七个是
- private void init_AliasStandardObjects() {
- configurationManager.addConfigurationProvider(new BeanSelectionProvider());
- }
private void init_AliasStandardObjects() {
configurationManager.addConfigurationProvider(new BeanSelectionProvider());
}
-------------------------------------------------------------------------------------------------
执行完七个init_*方法后,Dispatcher的#init()会接着调用#init_PreloadConfiguration(),构建一个用于依赖注射的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);
- ObjectTypeDeterminer objectTypeDeterminer = container
- .getInstance(ObjectTypeDeterminer.class);
- ObjectTypeDeterminerFactory.setInstance(objectTypeDeterminer);
- return 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);
ObjectTypeDeterminer objectTypeDeterminer = container
.getInstance(ObjectTypeDeterminer.class);
ObjectTypeDeterminerFactory.setInstance(objectTypeDeterminer);
return container;
}
此方法首先获取到ConfigurationManager中的Configuration对象,在#getConfiguration()内部,调用上边6步添加到ConfigurationManager的ConfigurationProviders的#register()方法。
- public synchronized Configuration getConfiguration() {
- if (configuration == null) {
- setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));
- try {
- configuration.reload(getConfigurationProviders());
- } catch (ConfigurationException e) {
- setConfiguration(null);
- throw e;
- }
- } else {
- conditionalReload();
- }
- return configuration;
- }
public synchronized Configuration getConfiguration() {
if (configuration == null) {
setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));
try {
configuration.reload(getConfigurationProviders());
} catch (ConfigurationException e) {
setConfiguration(null);
throw e;
}
} else {
conditionalReload();
}
return configuration;
}
其中的重点就是DefaultConfiguration的#reload()方法。
- public synchronized void reload(List providers) throws ConfigurationException {
- packageContexts.clear();
- loadedFileNames.clear();
- ContainerProperties props = new ContainerProperties();
- ContainerBuilder builder = new ContainerBuilder();
- for (ConfigurationProvider configurationProvider : providers)
- {
- configurationProvider.init(this);
- configurationProvider.register(builder, props);
- }
- props.setConstants(builder);
- builder.factory(Configuration.class, new Factory() {
- public Configuration create(Context context) throws Exception {
- return DefaultConfiguration.this;
- }
- });
- try {
- // Set the object factory for the purposes of factory creation
- ObjectFactory.setObjectFactory(new ObjectFactory());
- container = builder.create(false);
- objectFactory = container.getInstance(ObjectFactory.class);
- ObjectFactory.setObjectFactory(objectFactory);
- for (ConfigurationProvider configurationProvider : providers)
- {
- container.inject(configurationProvider);
- configurationProvider.loadPackages();
- }
- rebuildRuntimeConfiguration();
- } finally {
- ObjectFactory.setObjectFactory(null);
- }
- }