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(五)之處理流程》。