Struts的執行相當於分為兩個階段,預加載階段和執行階段,預加載階段是指在Tomcat啟動之時就開始執 行的內容,而此時我們並未真正進入跳轉邏輯,這篇博客我們來分析一下預加載階段。
配置文件
還記得web.xml中關於Struts的Servlet是如何配置的嗎?
<servlet-
name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>2</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- Standard Action Servlet Mapping -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
其中<load-on-startup>2</load-on-startup>指的就是在 Tomcat啟動之時即執行,實際只要數字大於0,意思就是Tomcat啟動即執行,為了進入調試,我們把這裡改為0 。
<load-on-startup>0</load-on-startup>
主函數init()
經過調 試發現,當執行完此函數,Struts的預加載階段即結束,所以我們主要來看這個函數即可。
/**
* <p>Initialize this servlet. Most of the processing has been factored into
* support methods so that you can override particular functionality at a
* fairly granular level.</p>
*
* @exception ServletException if we cannot configure ourselves correctly
*/
public void init() throws ServletException {
// Wraps the entire initialization in a try/catch to better handle
// unexpected exceptions and errors to provide better feedback
// to the developer
try {
initInternal();
initOther();
initServlet();
getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);
initModuleConfigFactory();
// Initialize modules as needed
ModuleConfig moduleConfig = initModuleConfig("", config);
initModuleMessageResources(moduleConfig);
initModuleDataSources(moduleConfig);
initModulePlugIns(moduleConfig);
moduleConfig.freeze();
Enumeration names = getServletConfig().getInitParameterNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
if (!name.startsWith("config/")) {
continue;
}
String prefix = name.substring(6);
moduleConfig = initModuleConfig
(prefix, getServletConfig().getInitParameter(name));
initModuleMessageResources(moduleConfig);
initModuleDataSources(moduleConfig);
initModulePlugIns(moduleConfig);
moduleConfig.freeze();
}
this.initModulePrefixes(this.getServletContext());
this.destroyConfigDigester();
} catch (UnavailableException ex) {
throw ex;
} catch (Throwable t) {
// The follow error message is not retrieved from internal message
// resources as they may not have been able to have been
// initialized
log.error("Unable to initialize Struts ActionServlet due to an "
+ "unexpected exception or error thrown, so marking the "
+ "servlet as unavailable. Most likely, this is due to an "
+ "incorrect or missing library dependency.", t);
throw new UnavailableException(t.getMessage());
}
}
很明顯init函數中執行有其它函數,為了簡明扼要,這些函數的代碼不再完全照搬,碰到重要或是 經典的代碼片段我會放進來。
調用函數
initInternal()
此函數的作用是,初始化內部 文件ActionResources.properties。
initOther()
此函數的作用是:指定struts-config.xml的 路徑,默認為/WEB-INF/struts-config.xml;同時注冊ConvertUtils的數據類型,例如:
ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class); ConvertUtils.register(new BigIntegerConverter(null), BigInteger.class);
initServlet()
此函數的作用是:讀取struts在web.xml中的配置信息,例如do/action、url等;獲取web程序部署信 息。
與ModuleConfig相關
getServletContext().setAttribute
(Globals.ACTION_SERVLET_KEY, this);
initModuleConfigFactory();
// Initialize modules as needed
ModuleConfig moduleConfig = initModuleConfig("", config);
initModuleMessageResources(moduleConfig);
initModuleDataSources(moduleConfig);
initModulePlugIns(moduleConfig);
moduleConfig.freeze();
Enumeration names = getServletConfig().getInitParameterNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
if (!name.startsWith("config/")) {
continue;
}
String prefix = name.substring(6);
moduleConfig = initModuleConfig
(prefix, getServletConfig().getInitParameter(name));
initModuleMessageResources(moduleConfig);
initModuleDataSources(moduleConfig);
initModulePlugIns(moduleConfig);
moduleConfig.freeze();
}
這段代碼的作用是,將web.xml中的Struts配置文件初始化為ModuleConfig對象,將 struts-config中的MessageResource、DataSource、PlugIn也都初始化為對象,保存到ServletContext中。不 同的是,while循環外操作的是web.xml裡 ActionServlet配置中config初始化參數指定的Struts配置文件; while循環內操作的是web.xml裡 ActionServlet配置中以"config/"開頭的初始化參數指定的 Struts配置文件,這樣的區別造成前者會產生沒有前綴的ModuleConfig對象到ServletConfig中,後者會產生 帶前綴的ModuleConfig對象放到ServletContext中,前綴為“config/”後的字符串。
initModulePrefixes(this.getServletContext());
此函數的作用是將循環產生的所有前綴生 成一個String數組,放到ServletContext中。
destroyConfigDigester();
此函數的作用是將 ActionServlet類的configDigester的值改為為null。
執行順序圖

這篇文章主要是分析了在Tomcat啟動時struts的預處理情況,在struts執行邏輯處理時是如 何處理的,請看我的博客《層層遞進Struts1(五)之處理流程》。