Struts源码学习 — ActionServlet的初始化
关键字: struts actionservlet
Struts版本:1.2.9
ActionServlet的初始化由org.apache.struts.action.ActionServlet类的init()方法实现,代码如下:
-
-
-
-
-
-
-
- public void init() throws ServletException {
-
-
-
-
- try {
- initInternal();
- initOther();
- initServlet();
-
- getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);
- initModuleConfigFactory();
-
- 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) {
-
-
-
-
- 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());
- }
- }
看起来代码行数不多,大部分都是对另外方法的调用,其中有些方法挖开比较简单,而有些很繁琐,为了避免这篇文章过长,对于比较繁琐的方法调用我会另开文章来说。
该方法初始化Struts的内部资源文件,该文件路径由ActionServlet的internalName字段指定,默认值是org.apache.struts.action.ActionResources,即Struts的JAR包里的org/apache/struts.action.ActionResources.properties及其国际化版本文件。该文件给出了一些应用运行时,由Struts产生的信息,包括一些异常报错信息,从这里可以看出,我们完全可以让Struts自身抛出的异常信息中文化。
该方法做了3件事:
如果web.xml里ActionServlet的配置中给出了config初始化参数,将该参数的值赋给ActionServlet的config字段;
如果web.xml里ActionServlet的配置中给出了convertNull初始化参数,如果该参数值是true、yes、on、y、1中的一个,将ActionServlet的convertNull字段设为true;
如果ActionServlet的convertNull字段值为true,则覆盖Apache Commons BeanUtils中几个基本数据类型包装类的转换器的默认实现,使当转换数据类型失败时,返回null,默认的实现是返回非null值。关于Struts使用的数据类型转换器
这个方法挖开后行数不算少,但其主要作用总结就一句话:将web.xml里ActionServlet配置中的url-pattern的值赋给ActionServlet类的servletMapping字段。实现方式是用Apache Commons Digester解析web.xml,用Digester内置的CallMethodRule和CallParamRule使web.xml被解析时,自动调用ActionServlet类的addServletMapping(String servletName, String urlPattern)方法。
- getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);
将ActionServlet实例设置为ServletContext的一个属性。
- initModuleConfigFactory();
如果web.xml里ActionServlet配置中给出了configFactory初始化参数,将其值指定的类做为Struts的ModuleConfigFactory,该值应该是一个完全限定类名,Struts默认ModuleConfigFactory的实现是org.apache.struts.config.impl.DefaultModuleConfigFactory。
-
- 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();
- }
把这段代码放到一起说,是因为它们做的是同一件事,只是操作的对象不同。
从代码上很容易看出,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中,用来区分各模块,方便团队开发。初始化ModuleConfig详解
- this.initModulePrefixes(this.getServletContext());
将上面while循环内产生的所有前缀生成一个String数组,放到ServletContext里。
- this.destroyConfigDigester();
将ActionServlet类的configDigester字段重置为null。