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中。关键代码如下:

protected void initServlet() throws ServletException {

        // Remember our servlet name
        this.servletName = getServletConfig().getServletName();

        // Prepare a Digester to scan the web application deployment descriptor
        Digester digester = new Digester();
        digester.push(this);
        digester.setNamespaceAware(true);
        digester.setValidating(false);

        // Register our local copy of the DTDs that we can find
        for (int i = 0; i < registrations.length; i += 2) {
            URL url = this.getClass().getResource(registrations[i+1]);
            if (url != null) {
                digester.register(registrations[i], url.toString());
            }
        }

        // Configure the processing rules that we need
        digester.addCallMethod("web-app/servlet-mapping",
                               "addServletMapping", 2);
        digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
        digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);       

        InputStream input =
            getServletContext().getResourceAsStream("/WEB-INF/web.xml");

        try {
            digester.parse(input);

        } catch (IOException e) {
            log.error(internal.getMessage("configWebXml"), e);
            throw new ServletException(e);

        } catch (SAXException e) {
            log.error(internal.getMessage("configWebXml"), e);
            throw new ServletException(e);

        } finally {
            try {
                input.close();
            } catch (IOException e) {
                log.error(internal.getMessage("configWebXml"), e);
                throw new ServletException(e);
            }
        }
    }

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

    4、initModuleConfigFactory()

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

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

 // 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();
            }

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

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

抽象工厂模式类图


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

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值