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);
- }
- }