struts1源码阅读(2)

    在第一章中,我们讲到在ActionServlet初始化时,不同的模块会初始化不同的ModuleConfig对象。但struts1到底是如何初始化ModuleConfig对象的,当时并没有详细叙述。这些内容将是本章的重点。

    struts1会根据web.xml中的配置,对每个模块都创建一个ModuleConfig对象,而每个模块可能会有多个struts的配置文件。在调用initModuleConfig()方法进行初始化时,会创建一个Digester对象,解析struts配置文件的工作就完全交由Digester负责了。

    Digester也是Apache下的一个开源框架,主要功能就是将XML解析成java对象,它对SAX进行封装。Digester具体的使用就不赘述了,这里列出我觉得struts1中用到的几个比较重要的类:

    1、Rule:在解析某个元素时执行的动作。

    2、RuleSet:配置一系列完整的相关Rule定义。Struts1对struts的配置文件中所有的元素均由ConfigRuleSet来处理。

    3、Rules:Rule实例的集合,可以通过制定元素对应的规则。

    4、Digester:解析XML的主要类。

    创建Digester对象的方法为:

protected Digester initConfigDigester() throws ServletException {

        // :FIXME: Where can ServletException be thrown?

        // Do we have an existing instance?
        if (configDigester != null) {
            return (configDigester);
        }

        // Create a new Digester instance with standard capabilities
        configDigester = new Digester();
        configDigester.setNamespaceAware(true);
        configDigester.setValidating(this.isValidating());
        configDigester.setUseContextClassLoader(true);
        configDigester.addRuleSet(new ConfigRuleSet());
        for (int i = 0; i < registrations.length; i += 2) {
            URL url = this.getClass().getResource(registrations[i+1]);
            if (url != null) {
                configDigester.register(registrations[i], url.toString());
            }
        }

        this.addRuleSets();

        // Return the completely configured Digester instance
        return (configDigester);
    }

    configDigester.addRuleSet(new ConfigRuleSet())最主要的目的就是调用RuleSet.addRuleInstances(),将struts配置文件的元素和规则进行对应。在ConfigRuleSet()方法中,将struts配置文件的所有元素都进行了标识,这里摘出部分:

digester.addFactoryCreate
            ("struts-config/action-mappings/action",
             new ActionMappingFactory());
        digester.addSetProperties
            ("struts-config/action-mappings/action");
        digester.addSetNext
            ("struts-config/action-mappings/action",
             "addActionConfig",
             "org.apache.struts.config.ActionConfig");

        digester.addSetProperty
            ("struts-config/action-mappings/action/set-property",
             "property", "value");

    这里的代码片段实际上是在创建一些Rule,并将这rule放到Rules。如果从面向对象的角度来看,实际上是分成两部分。将当前要处理的元素看成是一个对象,第一部分就是创建一个对象(此处是生成对象的工厂),第二部分就是为这个对象设置属性。不知道这么说是不是好理解一些,当然,前提是要对Digester有一定的了解,我在看这些代码时,也花了一些时间去看Digester的文档和源码。

    在创建Digester对象时,将元素与规则进行了映射。Digester对象在解析XML文档时,当开始解析标签时,会对碰到的各个标签用“/”拼接起来。当处理完某个元素时,会将该字符串最后“/”及之后的字符剔除,形成新的字符串。根据拼接的字符串,找到对应的Rule对象进行处理。之前也提到,对于每个标签,会生成一个对象,该对象在标签进行解析时会放入到Digester的栈中,解析完该标签后,会从栈处弹出。

    拿解析action的代码片段为例,ActionMappingFactory工厂对象会被封装到FactoryCreateRule对象(Rule)中。在开始对action标签进行解析时,会将生成的ActionMapping对象放入到栈中,并对action标签元素属性进行解析,取栈顶元素进行赋值。同时对标签<set-property>进行解析时,也会对栈顶元素进行赋值。有一个特殊的地方需要说明,digester.addSetNext()是创建一个SetNextRule对象,在对标签<action>解析结束时,调用栈顶倒数第二个对象的addActionConfig方法,该方法的参数即为栈顶第一个元素。

    以上只是对部分代码进行了描述,实际上Digester在进行解析时,会将每个标签看成一个对象(实际上依据你生成的Rule可能会有例外,比如:<set-property>),然后利用栈对这些对象进行深度遍历,每次解析完一个标签,就将该标签对应的对象从栈中弹出。下面用一个图来描述:

struts1解析配置文件

    在解析之前,会将生成的ModuleConfig对象放入栈。

    在解析<action>标签时,将创建的ActionMapping对象放入栈中,在解析<action>标签的子节点<exception>时,会将ExceptionConfig对象放入栈中。一直到最后一个子节点。当解析完一个标签时,就将其从栈顶弹出。

    实际上,struts配置文件中的标签对应的类,基本上都是在org.apache.struts.config包中,并且以Config结尾。如<action>对应的ActionMappping,它的父类是ActionConfig。

    在解析配置文件时,有四个是用工厂类来实现的。分别是<action>、<action/forward>、<form-bean>、<global-forwards/forward>。这些标签有个className属性,其负责设置标签对应的设置类。如果没有设置,则取ModuleConfig对象的默认值,分别为:

/**
     * The default class name to be used when creating action form bean
     * instances.
     */
    protected String actionFormBeanClass = "org.apache.struts.action.ActionFormBean";
    
    /**
     * The default class name to be used when creating action mapping instances.
     */
    protected String actionMappingClass = "org.apache.struts.action.ActionMapping";
    
    /**
     * The default class name to be used when creating action forward instances.
     */
    protected String actionForwardClass = "org.apache.struts.action.ActionForward";

    实际上,ibatis在解析配置文件时,也用的这种思想。每个标签都有一个config对象与之对应,这应该就是传说中的面向对象思想吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值