2、Dispatcher dispatcher = init.initDispatcher(config);
這行代碼是struts2初始化的核心部分(該方法是InitOperations中的方法)方法的具體內容如下:
1:Dispatcher dispatcher = createDipatcher(filterConfig);
/**
* 創建一個dispatcher實例,通過給定的servlet容器和配置項
* @param servletContext servlet容器
* @param initParams T 配置項
*/
public Dispatcher(ServletContext servletContext, Map<String, String> initParams) {
//初始化參數
this.servletContext = servletContext;
this.initParams = initParams;
}
改代碼的主要作用是初始化一個Dispatcher對象,其createDispatcher(FilterConfig filterConfig)爲InitOperations中的方法,該方法的具體內容如下:
/**
* 創建一個Dispatcher
*/
private Dispatcher createDispatcher( HostConfig filterConfig ) {
//把filterConfig中的配置參數以鍵值對的Map形式組織起來
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);
}
//返回一個Dispatcher對象,並把servlet容器,和組織的Map傳遞過去
return new Dispatcher(filterConfig.getServletContext(), params);
}
其中調用了Dispatcher的構造方法
在這個構造方法中初始化了兩個參數;分別爲:
private ServletContext servletContext;//servlet容器
private Map<String, String> initParams;//配置項
至此Dispatcher的初始化完成;需要注意的是初始化過程中對兩個參數的設定
2:dispatcher.init();改代碼是核心中的核心,其是Dispatcher(org.apache.struts2.dispatcher)中的方法,該方法的具體內容如下:
/**
* 加載配置項,包括xml和零配置策略還有更新選項設置,包括是否需要重新加載配置和資源文件
*/
public void init() {
//如果configurationManager爲空,則創建一個該對象
if (configurationManager == null) {
//初始化configurationManager對象
configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
}
try {
//初始化default.properties配置文件
①init_DefaultProperties(); // [1],第一步加載的是default.properties
②init_TraditionalXmlConfigurations(); // [2] 加載struts-defaults.xml,struts-plugin.xml,struts.xml這三個文件的provider
③init_LegacyStrutsProperties(); // [3] 加載LegacyPropertiesConfigurationProviders
④init_CustomConfigurationProviders(); // [5] 加載用戶自定義的配置解析文件
⑤init_FilterInitParameters() ; // [6] 加載filter中的參數
⑥init_AliasStandardObjects() ; // [7] 加載BeanSelectionProvider
//進行加載前進行的配置初始化
1: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爲空,則創建一個該對象
if (configurationManager == null) {
//初始化configurationManager對象
ConfigurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
}
這段代碼的主要作用是初始化一個configurationManager對象;這個對象是Dispatcher中的屬性
private ConfigurationManager configurationManager;
createConfigurationManager(String name)是Dispatcher中的方法,該方法的具體內容如下:
/**
* 創建一個configurationManager對象,並設置其默認框架名
* @param name
* @return
*/
protected ConfigurationManager createConfigurationManager(String name) {
return new ConfigurationManager(name);
}
調用了ConfigurationManager(com.opensymphony.xwork2.config)的構造方法,其構造方法具體內容如下
/**
* 可以設定默認框架名
* @param name 此時爲struts
*/
public ConfigurationManager(String name) {
this.defaultFrameworkBeanName = name;
}
該構造方法的具體作用有兩個,初始化默認FrameWork的名稱該參數是ConfigurationManager中的
protected String defaultFrameworkBeanName;
而BeanSelectionProvider.DEFAULT_BEAN_NAME這個靜態常量的具體值爲
public static final String DEFAULT_BEAN_NAME = "struts";
BeanSelectionProvider(org.apache.struts2.config)這個類的具體作用將會在後面講到
自此初始化ConfigurationManager對象結束
①init_DefaultProperties(); // [1],第一步加載的是default.properties
該方法屬於Dispatcher類,該方法的具體內容如下:
/**
* 把DefaultPropertiesProvider放入configurationManager對象的containerProvider中
*/
private void init_DefaultProperties() {
configurationManager.addContainerProvider(new DefaultPropertiesProvider());
}
其中調用了ConfigurationManager的addContainerProvider方法,該方法的具體內容如下:
/**
* 添加一個配置provider到ConfigurationProviders列表中。一個給定的ConfigurationProvider可能被添加多次
*
* @param provider將要被註冊的ConfigurationProvider
*/
public void addContainerProvider(ContainerProvider provider) {
/**
* 如果該provider存在,則不進行添加
*/
if (!containerProviders.contains(provider)) {
containerProviders.add(provider);
}
}
其中containerProviders是ConfigurationManager中的一個參數
private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<ContainerProvider>();
DefaultPropertiesProvider(org.apache.struts2.config)這個方法繼承自
LegacyPropertiesConfigurationProvider(org.apache.struts2.config)(這個類在後面會進行介紹)而LegacyPropertiesConfigurationProvider實現了ConfigurationProvider接口
而ConfigurationProvider(com.opensymphony.xwork2.config)的具體內容如下
/**
* 這個接口繼承了ContainerProvider,和PackageProvider接口
*/
public interface ConfigurationProvider extends ContainerProvider, PackageProvider {
}
其中ContainerProvider(com.opensymphony.xwork2.config)的主要內容如下:
public interface ContainerProvider {
/**
* 當被從configuratinManager的時候調用
*/
public void destroy();
/**
* 初始化配置信息
* @param configuration The configuration
* @throws ConfigurationException If anything goes wrong
*/
public void init(Configuration configuration) throws ConfigurationException;
/**
* 這個ContainerProvider是否需要重新裝載其配置
*/
public boolean needsReload();
/**
* 爲Container註冊bean、properties
*
* @param builder The builder to register beans with
* @param props The properties to register constants with
* @throws ConfigurationException If anything goes wrong
*/
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException;
}
該接口主要定義了4個方法分別爲:destory(),init(Configuration configuration),needsReload(),register(ContainerBuilder builder, LocatableProperties props)
這是個方法的具體用處在後面會進行介紹
而PackageProvider(com.opensymphony.xwork2.config)的具體內容如下
public interface PackageProvider {
/**
* 初始化Configuration
* @param configuration 配置
* @throws ConfigurationException If anything goes wrong
*/
public void init(Configuration configuration) throws ConfigurationException;
/**
* 這個PackageProvider是否需要重新被配置
*/
public boolean needsReload();
/**
* 爲這個配置加載Package
* @throws ConfigurationException
*/
public void loadPackages() throws ConfigurationException;
}
因此只要實現ConfigurationProvider接口的類,都可被添加到ConfigurationManager的containerProviders這個屬性中
而DefaultPropertiesProvider這個類的主要作用是讀取default.properties中的配置信息放入ContainerBuilder中,
在這裏調用了DefaultPropertiesProvider的默認構造方法,該構造方法只是創建了一個DefaultPropertiesProvider對象,未進行任何其他操作
至於該類的其他作用將在後面進行介紹
②init_TraditionalXmlConfigurations(); // [2] 加載struts-defaults.xml,struts-plugin.xml,struts.xml這三個文件的provider
該方法屬於Dispatcher的方法,方法的具體內容如下:
/**
* 加載各類xml配置
*/
private void init_TraditionalXmlConfigurations() {
//查看web.xml的Filter中是否配置了config這個參數
String configPaths = initParams.get("config");
if (configPaths == null) {
//如果沒有配置,則採用默認的設置
configPaths = DEFAULT_CONFIGURATION_PATHS;
}
//把configpaths分離成3個string;分別爲struts-default.xml;struts-plugin.xml;struts.xml
String[] files = configPaths.split("\\s*[,]\\s*");
//對分離的files進行遍歷:struts-default.xml
for (String file : files) {
if (file.endsWith(".xml")) {//如果這些文件是以.xml結尾的話
if ("xwork.xml".equals(file)) {
//如果文件名等於xwork.xml的話,
configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false));
} else {
//向configurationManager的containerProvider中添加下面的strutsxmlconfigurationprovider
configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
}
} else {
//如果不是以.xml結尾的文件的話,拋出一個異常
throw new IllegalArgumentException("Invalid configuration file name");
}
}
}
上述代碼中如果file和xwork.xml相等則執行
configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false));
否則執行
configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
方法createXmlConfigurationProvider(file, false)的具體內容如下
/**
* 創建一個xmlconfigurationProvider對象,用來解析xwork.xml
* @param filename 文件名
* @param errorIfMissing 如果找不到該文件的話,的處理辦法,是否報錯,是否拋出異常
* @return
*/
protected XmlConfigurationProvider createXmlConfigurationProvider(String filename, boolean errorIfMissing) {
return new XmlConfigurationProvider(filename, errorIfMissing);
}
這裏調用了XmlConfigurationProvider(com.opensymphony.xwork.config.providers)的構造方法,該構造方法的具體內容如下
/**
* 默認的構造方法,前兩個構造方法在內部都調用該構造方法來作爲初始化改對象的選項
* @param filename struts-default.xml
* @param errorIfMissing
*/
public XmlConfigurationProvider(String filename, boolean errorIfMissing) {
//設定文件名
this.configFileName = filename;
//出錯信息
this.errorIfMissing = errorIfMissing;
//dtd約束配置
Map<String, String> mappings = new HashMap<String, String>();
mappings.put("-//Apache Struts//XWork 2.3//EN", "xwork-2.3.dtd");
mappings.put("-//Apache Struts//XWork 2.1.3//EN", "xwork-2.1.3.dtd");
mappings.put("-//Apache Struts//XWork 2.1//EN", "xwork-2.1.dtd");
mappings.put("-//Apache Struts//XWork 2.0//EN", "xwork-2.0.dtd");
mappings.put("-//Apache Struts//XWork 1.1.1//EN", "xwork-1.1.1.dtd");
mappings.put("-//Apache Struts//XWork 1.1//EN", "xwork-1.1.dtd");
mappings.put("-//Apache Struts//XWork 1.0//EN", "xwork-1.0.dtd");
setDtdMappings(mappings);
}
在這個構造方法裏面主要進行了如下操作:
1)初始化了文件名this.configFileName = filename;
2)初始化錯誤處理方法this.errorIfMissing = errorIfMissing;
3)添加了dtd約束文件
setDtdMappings(mappings);方法的具體代碼如下:
//設定DTD約束
public void setDtdMappings(Map<String, String> mappings) {
this.dtdMappings = Collections.unmodifiableMap(mappings);
}
其中包括XmlConfigurationProvider的屬性
private Map<String, String> dtdMappings;
該類負責解析xml文件
方法createStrutsXmlConfigurationProvider(file, false, servletContext)的具體內容如下
/**
* 創建一個strutsxmlconfigurationprovider對象
* @param filename 配置文件名
* @param errorIfMissing 錯誤處理方式
* @param ctx servlet容器
* @return
*/
protected XmlConfigurationProvider createStrutsXmlConfigurationProvider(String filename, boolean errorIfMissing, ServletContext ctx) {
return new StrutsXmlConfigurationProvider(filename, errorIfMissing, ctx);
}
這裏調用了StrutsXmlConfigurationProvider(org.apache.struts2.config)的默認構造方法
/**
* 創建一個配置provider
* @param filename 文件名
* @param errorIfMissing 如果該文件未找到,我們是否需要拋出異常
* @param ctx Servlet容器
*/
public StrutsXmlConfigurationProvider(String filename, boolean errorIfMissing, ServletContext ctx) {
super(filename, errorIfMissing);//調用父類的默認構造方法
this.servletContext = ctx;//初始化servlet容器
this.filename = filename;//設置文件名 struts-default.xml
reloadKey = "configurationReload-"+filename;//?這裏是什麼意思,目前不瞭解
Map<String,String> dtdMappings = new HashMap<String,String>(getDtdMappings());//獲取父類的dtdmapping,並添加struts2的DTD約束
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);//設置新添加struts2的DTD約束
/**
* 以下這段代碼,不懂具體含義是什麼
*/
File file = new File(filename);
if (file.getParent() != null) {
this.baseDir = file.getParentFile();
}
}
在該構造方法裏進行了如下操作
1)首先調用父類的構造方法,設置文件名,設置錯誤處理方式
2)初始化 this.servletContext = ctx;
3)設置文件名 this.filename = filename;
4)這行代碼的主要作用不了解 reloadKey = "configurationReload-"+filename;
5)獲取父類配置的dtd約束文件
6)在dtd中添加struts2的dtd約束文件
7)調用父類的方法,設置新的dtd約束文件
至此,struts-default.xml,struts-plugin.xml,struts.xml三個文件的解析類都放入ConfigurationManager的containerProviders中。具體解析方法在後面會進行介紹
③init_LegacyStrutsProperties(); // [3] 加載LegacyPropertiesConfigurationProviders
該方法屬於Dispatcher的方法,方法的具體內容如下:
/**
* 把LegacyPropertiesConfigurationProvider添加到configurationManager對象的containerProvider中去;
* 具體這個provider解析的是什麼,目前不瞭解
*/
private void init_LegacyStrutsProperties() {
configurationManager.addContainerProvider(new LegacyPropertiesConfigurationProvider());
}
這裏的LegacyPropertiesConfigurationProvider(org.apache.struts2.config)被DefaultPropertiesProvider繼承,目前該類的主要作用不是很清楚
同時,這裏只是創建了一個該類的實例,未進行任何其他操作,因此在這裏不做過多介紹,該類的其他具體作用將在後面進行介紹
④init_CustomConfigurationProviders(); // [5] 加載用戶自定義的配置解析文件
該方法屬於Dispatcher的方法,方法的具體內容如下:
/**
* 加載用戶自定義的configProviders文件
*/
private void init_CustomConfigurationProviders() {
//從web.xml的Filter的配置信息裏面查找configProviders的配置
String configProvs = initParams.get("configProviders");
if (configProvs != null) {
//吧用戶配置的參數用,分割成一個string數組;這些類必須實現ConfigurationProvider接口
String[] classes = configProvs.split("\\s*[,]\\s*");
for (String cname : classes) {//對用戶配置的文件進行遍歷,添加到containerProvider中
try {
//通過java反射機制生成實體對象
Class cls = ClassLoaderUtil.loadClass(cname, this.getClass());
ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();
//加載到configurationManager的containerProvider中
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);
}
}
}
}
該方法的組要作用是,檢索web.xml中的Filter的配置信息,查看用戶是否配置了ConfigProvider選項,如果配置了該選項,首先對該選項的內容進行解析
同時,利用java的反射機制生成一個該類的實例,添加到ConfigurationManager的containerProviders中
⑤init_FilterInitParameters() ; // [6] 加載filter中的參數
該方法屬於Dispatcher的方法,方法的具體內容如下:
/**
* 把web.xml中配置的參數放入configurationManager的cotainerprovider中去
*/
private void init_FilterInitParameters() {
configurationManager.addContainerProvider(new ConfigurationProvider() {
public void destroy() {
}
public void init(Configuration configuration) throws ConfigurationException {
}
public void loadPackages() throws ConfigurationException {
}
public boolean needsReload() {
return false;
}
//把web.xml中配置的fileter中的參數放入props中
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
props.putAll(initParams);
}
});
}
該方法的具體作用是在該方法內部調用configurationManager的addContainerProvider方法,添加了一個匿名實現了ConfigurationProvider接口的類
該匿名內部類的主要作用是加載web.xml配置文件在Filter中配置的參數
⑥init_AliasStandardObjects() ; // [7] 加載BeanSelectionProvider
該方法是Dispatcher中的方法,該方法的具體內容如下:
/**
* 加載BeanSelectionProvider到configurationManager的containerprovider中去
*/
private void init_AliasStandardObjects() {
configurationManager.addContainerProvider(new BeanSelectionProvider());
}
該方法的主要作用是裝載BeanSelectionProvider(org.apache.struts2.config)在這裏只是創建了一個新的BeanSelectionProvider對象的實例,未進行其他操作
至於該類的作用和具體含義將在後面進行介紹