一:介紹
在tomcat的啟動過程中,tomcat會讀取/WEB-INF/web.xml檔案中的配置資訊進行一些初始化的工作,而Struts的啟動工作就從這裡開始.
在web.xml檔案中有如下的配置資訊:
<servlet><br /> <servlet-name>action</servlet-name><br /> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class><br /> <init-param><br /> <param-name>config</param-name><br /> <param-value>/WEB-INF/struts-config.xml</param-value><br /> </init-param><br /> <init-param><br /> <param-name>debug</param-name><br /> <param-value>3</param-value><br /> </init-param><br /> <init-param><br /> <param-name>detail</param-name><br /> <param-value>3</param-value><br /> </init-param><br /> <load-on-startup>0</load-on-startup><br /> </servlet><br /> <servlet-mapping><br /> <servlet-name>action</servlet-name><br /> <url-pattern>*.do</url-pattern><br /> </servlet-mapping>
即表示tomcat啟動的時候會初始化org.apache.struts.action.ActionServlet類.
ActionServlet繼承了,javax.servlet.http.HttpServlet.是個Servlet當然也就遵循Servlet的生命週期.</p><p>我們這裡複習一下Servlet的生命週期<br /> 1.Servlet執行個體被建立.<br /> 2. 調用init(ServletConfig config )方法.(在HttpServlet中<br /> 實際上在init(ServletConfig config ) 中調用了init()所以<br /> 我們可以覆蓋 init()方法來進行初例化)<br /> 3.接受客戶請求.調用service方法.(在HttpServelt中,會調用doGet<br /> 和doPost)<br /> 4. 調用destroy()方法.<br /> 5.執行個體被銷毀.
二:
Struts的ActionServlet的初始化
首先看一下init()的源碼:
/**<br /> * <p>Initialize this servlet. Most of the processing has been factored<br /> * into support methods so that you can override particular functionality<br /> * at a fairly granular level.</p><br /> *<br /> * @throws ServletException if we cannot configure ourselves correctly<br /> */<br /> public void init() throws ServletException {<br /> final String configPrefix = "config/";<br /> final int configPrefixLength = configPrefix.length() - 1;<br /> // Wraps the entire initialization in a try/catch to better handle<br /> // unexpected exceptions and errors to provide better feedback<br /> // to the developer<br /> try {<br /> initInternal();<br /> initOther();<br /> initServlet();<br /> initChain();<br /> getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);<br /> initModuleConfigFactory();<br /> // Initialize modules as needed<br /> ModuleConfig moduleConfig = initModuleConfig("", config);<br /> initModuleMessageResources(moduleConfig);<br /> initModulePlugIns(moduleConfig);<br /> initModuleFormBeans(moduleConfig);<br /> initModuleForwards(moduleConfig);<br /> initModuleExceptionConfigs(moduleConfig);<br /> initModuleActions(moduleConfig);<br /> moduleConfig.freeze();<br /> Enumeration names = getServletConfig().getInitParameterNames();<br /> while (names.hasMoreElements()) {<br /> String name = (String) names.nextElement();<br /> if (!name.startsWith(configPrefix)) {<br /> continue;<br /> }<br /> String prefix = name.substring(configPrefixLength);<br /> moduleConfig =<br /> initModuleConfig(prefix,<br /> getServletConfig().getInitParameter(name));<br /> initModuleMessageResources(moduleConfig);<br /> initModulePlugIns(moduleConfig);<br /> initModuleFormBeans(moduleConfig);<br /> initModuleForwards(moduleConfig);<br /> initModuleExceptionConfigs(moduleConfig);<br /> initModuleActions(moduleConfig);<br /> moduleConfig.freeze();<br /> }<br /> this.initModulePrefixes(this.getServletContext());<br /> this.destroyConfigDigester();<br /> } catch (UnavailableException ex) {<br /> throw ex;<br /> } catch (Throwable t) {<br /> // The follow error message is not retrieved from internal message<br /> // resources as they may not have been able to have been<br /> // initialized<br /> log.error("Unable to initialize Struts ActionServlet due to an "<br /> + "unexpected exception or error thrown, so marking the "<br /> + "servlet as unavailable. Most likely, this is due to an "<br /> + "incorrect or missing library dependency.", t);<br /> throw new UnavailableException(t.getMessage());<br /> }<br /> }
1、initInternal()
-------Initialize our internal MessageResources bundle
該方法初始化Struts的內部資源檔,該檔案路徑由ActionServlet的internalName欄位指定,預設值是org.apache.struts.action.ActionResources,即Struts的JAR包裡的org/apache/struts.action.ActionResources.properties及其國際化版本檔案。該檔案給出了一些應用運行時,由Struts產生的資訊,包括一些異常報錯資訊,從這裡可以看出,我們完全可以讓Struts自身拋出的異常資訊中文化。
2、initOther()
-----Initialize other global characteristics of the controller servlet
2.1 如果web.xml裡ActionServlet的配置中給出了config初始化參數,將該參數的值賦給ActionServlet的config欄位;<br />2.2 如果web.xml裡ActionServlet的配置中給出了convertNull初始化參數,如果該參數值是true、yes、on、y、1中的一個,將ActionServlet的convertNull欄位設為true;<br />2.3 如果ActionServlet的convertNull欄位值為true,則覆蓋Apache Commons BeanUtils中幾個基礎資料型別 (Elementary Data Type)封裝類的轉換器的預設實現,使當轉換資料類型失敗時,返回null,預設的實現是拋出異常。
3、initServlet()
-----Initialize the servlet mapping under which our controller servlet is being accessed
這個方法挖開後行數不算少,但其主要作用總結就一句話:將web.xml裡ActionServlet配置中的url-pattern的值賦給ActionServlet類的servletMapping欄位。實現方式是用Apache Commons Digester解析web.xml,用Digester內建的CallMethodRule和CallParamRule使web.xml被解析時,自動調用ActionServlet類的addServletMapping(String servletName, String urlPattern)方法。
關於digester類解析xml檔案請參考:
http://blog.csdn.net/wl_ldy/archive/2010/10/07/5925710.aspx
4、initChain()
Parse the configuration documents specified by the<br />chainConfig init-param to configure the default {@link<br />org.apache.commons.chain.Catalog} that is registered in the {@link CatalogFactory} instance for this application
5、getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this)
將ActionServlet執行個體以Globals.ACTION_SERVLET_KEY為key存在ServletContext對象中
6、initModuleConfigFactory()
如果web.xml裡ActionServlet配置中給出了
configFactory初始化參數,將其值指定的類做為Struts的ModuleConfigFactory,該值應該是一個完全限定類
名,Struts預設ModuleConfigFactory的實現是
org.apache.struts.config.impl.DefaultModuleConfigFactory。
7、// Initialize modules as needed<br /> ModuleConfig moduleConfig = initModuleConfig("", config);<br /> initModuleMessageResources(moduleConfig);<br /> initModulePlugIns(moduleConfig);<br /> initModuleFormBeans(moduleConfig);<br /> initModuleForwards(moduleConfig);<br /> initModuleExceptionConfigs(moduleConfig);<br /> initModuleActions(moduleConfig);<br /> moduleConfig.freeze();<br /> Enumeration names = getServletConfig().getInitParameterNames();<br /> while (names.hasMoreElements()) {<br /> String name = (String) names.nextElement();<br /> if (!name.startsWith(configPrefix)) {<br /> continue;<br /> }<br /> String prefix = name.substring(configPrefixLength);<br /> moduleConfig =<br /> initModuleConfig(prefix,<br /> getServletConfig().getInitParameter(name));<br /> initModuleMessageResources(moduleConfig);<br /> initModulePlugIns(moduleConfig);<br /> initModuleFormBeans(moduleConfig);<br /> initModuleForwards(moduleConfig);<br /> initModuleExceptionConfigs(moduleConfig);<br /> initModuleActions(moduleConfig);<br /> moduleConfig.freeze();<br /> }<br />把這段代碼放到一起說,是因為它們做的是同一件事,只是操作的對象不同。<br />從代碼上很容易看出,while迴圈外和內的代碼做的是同一件事,簡單說就是將web.xml裡給出的Struts設定檔初始化為ModuleConfig對象,將Struts設定檔裡給出的 MessageResource、DataSource、PlugIn也都初始化為對象,然後將這些對象都放到ServletContext裡。<br />不同的是,while迴圈外操作的是web.xml裡 ActionServlet配置中config初始化參數指定的Struts設定檔;while迴圈內操作的是web.xml裡 ActionServlet配置中以"config/"開頭的初始化參數指定的Struts設定檔。<br />while迴圈外的代碼執行完後,會產生一個預設的沒有首碼的 ModuleConfig對象放到ServletContext裡;while迴圈內的代碼執行完後,會產生N個有首碼的ModuleConfig對象放到ServletContext裡,N等於web.xml裡ActionServlet配置中以"config/"開頭的初始化參數的個數,它們的首碼是"config/"後的字串。這個首碼體現在訪問應用的URL中,用來區分各模組,方便團隊開發
8、this.initModulePrefixes(this.getServletContext());
將上面while迴圈內產生的所有首碼產生一個String數組,放到ServletContext裡。
9、this.destroyConfigDigester();
將ActionServlet類的configDigester欄位重設為null。
Come from:http://gemini.javaeye.com/category/8491?show_full=true