層層遞進Struts1(四)之預載入ActionServlet
Struts的執行相當於分為兩個階段,預載入階段和執行階段,預載入階段是指在Tomcat啟動之時就開始執行的內容,而此時我們並未真正進入跳轉邏輯,這篇部落格我們來分析一下預載入階段。
配置檔案
還記得web.xml中關於Struts的Servlet是如何配置的嗎?
其中<load-on-startup>2</load-on-startup>指的就是在Tomcat啟動之時即執行,實際只要數字大於0,意思就是Tomcat啟動即執行,為了進入除錯,我們把這裡改為0。<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>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(五)之處理流程》。