struts1源码阅读(1)

    用struts1也有不短的日子了,对于它的功能也有了一定的理解。基于此,抱着学习的态度,我计划在空闲时间来系统的看下struts1的源码。之所以说系统,是因为之前断断续续的也看过一些,但限于当时对struts1的了解,体会得可能还不深入,所以总是容易忘记看过的东西。但现在来读 struts1的源码,应该会更加合适一些,有几个方面的因素,而这几个因素,我觉得也可以用在阅读其他项目的源码上:

    1、首先,我对struts1的功能有了一定的了解,虽然还不够精通,但对其整体的框架和体系是有一定认知的;

    2、其次,能够区分struts1的各功能模块,这样在阅读源码时就会有的放矢,各个击破了。

struts1工作流程

    先让我们来看看struts1的工作流程,从宏观上对struts1的功能有个认知。

    从网上找了两张图:

    struts1的体系结构图:

struts1体系结构

    struts1的工作流程图:

struts1流程图

    1、初始化:struts框架的总控制器ActionServlet是一个Servlet,它在web.xml中配置成自动启动的

Servlet,在启动时总控制器会读取配置文件(struts-config.xml)的配置信息,为struts

中不同的模块初始化相应的对象。

    2、发送请求:用户提交表单或通过URLWEB服务器提交请求,请求的数据用HTTP协议传给web服务器。

    3、form填充:struts的总控制器ActionServlet在用户提交请求时将数据放到对应的form对象中的成员

变量中。

    4、派发请求:控制器根据配置信息对象ActionConfig将请求派发到具体的Action,对应的formBean一并

传给这个Action中的excute()方法。

    5、处理业务:Action一般只包含一个excute()方法,它负责执行相应的业务逻辑(调用其它的业务模块)

完毕后返回一个ActionForward对象。服务器通过ActionForward对象进行转发工作。

    6、返回响应:Action将业务处理的不同结果返回一个目标响应对象给总控制器。

    7、查找响应:总控制器根据Action处理业务返回的目标响应对象,找到对应的资源对象,一般情况下

jsp页面。

    8、响应用户:目标响应对象将结果传递给资源对象,将结果展现给用户。

struts1初始化

    下面开始我们的源码阅读之旅,首先,对struts1的初始化源码进行阅读。

    web容器在初始化或者初始化完成后,会在适当的时候初始化servlet。struts1中的ActionServlet类就是一个servlet,其会被web容器进行调用。

    首先会调用init()方法,该方法会执行如下动作:

    1、initInternal()

    初始化struts内部使用的消息资源。

    2、initOther()

    2.1 读取初始化参数config,如果在web.xml中对该参数进行了设置,则将ActionServlet类中的config字段设置上对应的值。该值记录的是默认情况下,struts配置文件的路径。

    2.2 读取初始化参数convertNull,如果设置为true(可为true、yes、on、y、1),则将原始类型的封装类默认值设置为null。

    3、initServlet()

    利用Digester组件解析web.xml,将当前servlet对应的<servlet-mapping>内容加载到ActionServlet中。关键代码如下:

  1. protected void initServlet() throws ServletException {  
  2.   
  3.         // Remember our servlet name  
  4.         this.servletName = getServletConfig().getServletName();  
  5.   
  6.         // Prepare a Digester to scan the web application deployment descriptor  
  7.         Digester digester = new Digester();  
  8.         digester.push(this);  
  9.         digester.setNamespaceAware(true);  
  10.         digester.setValidating(false);  
  11.   
  12.         // Register our local copy of the DTDs that we can find  
  13.         for (int i = 0; i < registrations.length; i += 2) {  
  14.             URL url = this.getClass().getResource(registrations[i+1]);  
  15.             if (url != null) {  
  16.                 digester.register(registrations[i], url.toString());  
  17.             }  
  18.         }  
  19.   
  20.         // Configure the processing rules that we need  
  21.         digester.addCallMethod("web-app/servlet-mapping",  
  22.                                "addServletMapping"2);  
  23.         digester.addCallParam("web-app/servlet-mapping/servlet-name"0);  
  24.         digester.addCallParam("web-app/servlet-mapping/url-pattern"1);         
  25.   
  26.         InputStream input =  
  27.             getServletContext().getResourceAsStream("/WEB-INF/web.xml");  
  28.   
  29.         try {  
  30.             digester.parse(input);  
  31.   
  32.         } catch (IOException e) {  
  33.             log.error(internal.getMessage("configWebXml"), e);  
  34.             throw new ServletException(e);  
  35.   
  36.         } catch (SAXException e) {  
  37.             log.error(internal.getMessage("configWebXml"), e);  
  38.             throw new ServletException(e);  
  39.   
  40.         } finally {  
  41.             try {  
  42.                 input.close();  
  43.             } catch (IOException e) {  
  44.                 log.error(internal.getMessage("configWebXml"), e);  
  45.                 throw new ServletException(e);  
  46.             }  
  47.         }  
  48.     }  

    在解析时,会调用ActionServlet类中的addServletMapping()方法,该方法会根据当前servlet对应servletName去匹配对应的url-pattern。

    4、initModuleConfigFactory()

    初始化创建模块配置对象的工厂类,将初始化参数configFactory指定的类名赋予ModuleConfigFactory类的factoryClass字段。

    5、对web.xml中配置的多个模块分别进行解析,生成不同的moduleConfig对象。主要代码如下:

  1. // Initialize modules as needed  
  2.            ModuleConfig moduleConfig = initModuleConfig("", config);  
  3.            initModuleMessageResources(moduleConfig);  
  4.            initModuleDataSources(moduleConfig);  
  5.            initModulePlugIns(moduleConfig);  
  6.            moduleConfig.freeze();  
  7.      
  8.            Enumeration names = getServletConfig().getInitParameterNames();  
  9.            while (names.hasMoreElements()) {  
  10.                String name = (String) names.nextElement();  
  11.                if (!name.startsWith("config/")) {  
  12.                    continue;  
  13.                }  
  14.                String prefix = name.substring(6);  
  15.                moduleConfig = initModuleConfig  
  16.                    (prefix, getServletConfig().getInitParameter(name));  
  17.                initModuleMessageResources(moduleConfig);  
  18.                initModuleDataSources(moduleConfig);  
  19.                initModulePlugIns(moduleConfig);  
  20.                moduleConfig.freeze();  
  21.            }  

    在方法initModuleConfig()中,会根据生成一个工厂对象,该工厂会根据各模块前缀生成不同的ModuleConfig对象。

    这里,很明显的使用到了抽象工厂模式。为了对抽象工厂模式有更深的理解,在这里也多说几句。

抽象工厂模式类图


    ModuleConfigFactory是一个抽象类,它有一个抽象方法createModuleConfig()供子类实现,该方法就是用来生产 ModuleConfig对象的。在Struts1中,有个默认的工厂实现类DefaultModuleConfigFactory,该类负责生产 ModuleConfigImpl对象。

    ModuleConfigFactory的实现子类可以在web.xml中进行配置,通过调用setFactoryClass()和createFactory()方法,可以生成具体的工厂类。

    抽象工厂模式定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
    在生成了ModuleConfig对象后,会利用Digester组件对struts的配置文件进行解析,解析后的内容会放入ModuleConfig对象。

 转载地址:  http://blog.csdn.net/duwenchao1986/article/details/8464794

原文地址:https://www.cnblogs.com/lishoubin/p/3211286.html