一:介绍
在tomcat的启动过程中,tomcat会读取/WEB-INF/web.xml文件中的配置信息进行一些初始化的工作,而Struts的启动工作就从这里开始.
在web.xml文件中有如下的配置信息:
<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>3</param-value> </init-param> <init-param> <param-name>detail</param-name> <param-value>3</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
即表示tomcat启动的时候会初始化org.apache.struts.action.ActionServlet类.
ActionServlet继承了,javax.servlet.http.HttpServlet.是个Servlet当然也就遵循Servlet的生命周期. 我们这里复习一下Servlet的生命周期 1.Servlet实例被创建. 2. 调用init(ServletConfig config )方法.(在HttpServlet中 实际上在init(ServletConfig config ) 中调用了init()所以 我们可以覆盖 init()方法来进行初例化) 3.接受客户请求.调用service方法.(在HttpServelt中,会调用doGet 和doPost) 4. 调用destroy()方法. 5.实例被销毁.
二: Struts的ActionServlet的初始化
首先看一下init()的源码:
/** * <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> * * @throws ServletException if we cannot configure ourselves correctly */ public void init() throws ServletException { final String configPrefix = "config/"; final int configPrefixLength = configPrefix.length() - 1; // 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(); initChain(); getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this); initModuleConfigFactory(); // Initialize modules as needed ModuleConfig moduleConfig = initModuleConfig("", config); initModuleMessageResources(moduleConfig); initModulePlugIns(moduleConfig); initModuleFormBeans(moduleConfig); initModuleForwards(moduleConfig); initModuleExceptionConfigs(moduleConfig); initModuleActions(moduleConfig); moduleConfig.freeze(); Enumeration names = getServletConfig().getInitParameterNames(); while (names.hasMoreElements()) { String name = (String) names.nextElement(); if (!name.startsWith(configPrefix)) { continue; } String prefix = name.substring(configPrefixLength); moduleConfig = initModuleConfig(prefix, getServletConfig().getInitParameter(name)); initModuleMessageResources(moduleConfig); initModulePlugIns(moduleConfig); initModuleFormBeans(moduleConfig); initModuleForwards(moduleConfig); initModuleExceptionConfigs(moduleConfig); initModuleActions(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()); } }
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字段; 2.2 如果web.xml里ActionServlet的配置中给出了convertNull初始化参数,如果该参数值是true、yes、on、y、1中的一个,将ActionServlet的convertNull字段设为true; 2.3 如果ActionServlet的convertNull字段值为true,则覆盖Apache Commons BeanUtils中几个基本数据类型包装类的转换器的默认实现,使当转换数据类型失败时,返回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 chainConfig init-param to configure the default {@link 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 ModuleConfig moduleConfig = initModuleConfig("", config); initModuleMessageResources(moduleConfig); initModulePlugIns(moduleConfig); initModuleFormBeans(moduleConfig); initModuleForwards(moduleConfig); initModuleExceptionConfigs(moduleConfig); initModuleActions(moduleConfig); moduleConfig.freeze(); Enumeration names = getServletConfig().getInitParameterNames(); while (names.hasMoreElements()) { String name = (String) names.nextElement(); if (!name.startsWith(configPrefix)) { continue; } String prefix = name.substring(configPrefixLength); moduleConfig = initModuleConfig(prefix, getServletConfig().getInitParameter(name)); initModuleMessageResources(moduleConfig); initModulePlugIns(moduleConfig); initModuleFormBeans(moduleConfig); initModuleForwards(moduleConfig); initModuleExceptionConfigs(moduleConfig); initModuleActions(moduleConfig); moduleConfig.freeze(); } 把这段代码放到一起说,是因为它们做的是同一件事,只是操作的对象不同。 从代码上很容易看出,while循环外和内的代码做的是同一件事,简单说就是将web.xml里给出的Struts配置文件初始化为ModuleConfig对象,将Struts配置文件里给出的 MessageResource、DataSource、PlugIn也都初始化为对象,然后将这些对象都放到ServletContext里。 不同的是,while循环外操作的是web.xml里 ActionServlet配置中config初始化参数指定的Struts配置文件;while循环内操作的是web.xml里 ActionServlet配置中以"config/"开头的初始化参数指定的Struts配置文件。 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