tomcat如何解析META-INF目录下的context.xml

前阵子,准备重新测试一下tomcat对context.xml中数据源的处理情况,当时我的context.xml是这样写的,并且放在web目录下的META-INF目录下

<?xml version='1.0' encoding='UTF-8'?>
<Context>
	<resource name="jdbc/xx" auth="Container" type="javax.sql.DataSource" password="123456"
			  driverClassName="com.mysql.jdbc.Driver"
			  username="root" url="jdbc:mysql://127.0.0.1/xx"
			  />
</Context>

并且相应的mysql.jar包已经放到tomcat的lib目录下,然后在进行运行之后,死活也找不到所配置的数据源信息。最后找了半天,错误原因也很简单的,并不是context.xml位置不正确。在上面的xml配置中,resource节点中的resource应该写首字母大写,即应该为Resource而不是resource。修改之后,一切正确了。

那么是什么原因导致tomcat找不到这里所写的小写的resource呢,这就涉及到tomcat内部对context.xml解析了。在tomcat内部,是通过ContextConfig类来用于处理context.xml信息,并通过Digester类来完成对context.xml的解析,在具体的解析过程中,正是因为对相应节点的匹配不成功,导致没有解析。但是不会发生错误。

在tomcat内部,使用ContextConfig来解析web.xml和context.xml,当仔细查看代码时,你会发现,解析web.xml和context.xml使用的是同一个类,即org.apache.tomcat.util.digester.Digester,通过使用不同的Rule对节点进行匹配,让匹配之后的Rule进行不同的操作,而Digester本身只做一个分发的作用,并不参与实际逻辑。整个流程可以由如下图所示:

那么在整个Context.xml解析中加入了哪些RuleSet呢,可以由如何创建contextDigester的过程得出,如下代码所示:(以下代码在ContextConfig类中)

    protected Digester createContextDigester() {
        Digester digester = new Digester();
        digester.setValidating(false);
        digester.setRulesValidation(true);
        HashMap<Class<?>, List<String>> fakeAttributes =
            new HashMap<Class<?>, List<String>>();
        ArrayList<String> attrs = new ArrayList<String>();
        attrs.add("className");
        fakeAttributes.put(Object.class, attrs);
        digester.setFakeAttributes(fakeAttributes);
        RuleSet contextRuleSet = new ContextRuleSet("", false);//用于解析在context.xml中常规的context选项
        digester.addRuleSet(contextRuleSet);
        RuleSet namingRuleSet = new NamingRuleSet("Context/");//用于解析如本文中的命名服务信息
        digester.addRuleSet(namingRuleSet);
        return digester;
    }

ContextRuleSet和NamingRuleSet是一个规则集合,在详细的addRuleInstances(Digester digester)中,才把最终的规则加入到digester中。在tomcat中,每一条规则的描述即由一个规则名和具体规则实现来表示。规则名,即从xml根节点名到子节点名的一个完整path,如context节点下的resource节点,就表示为Context/Resource。在NamingRuleSet中,我们可以看到为Resource节点增加了3个规则,如下所示:        

digester.addObjectCreate(prefix + "Resource",
                                 "org.apache.catalina.deploy.ContextResource");
        digester.addRule(prefix + "Resource", new SetAllPropertiesRule());
        digester.addRule(prefix + "Resource",
                new SetNextNamingRule("addResource",
                            "org.apache.catalina.deploy.ContextResource"));

其中第一个规则,即创建一个ContextResource对象,即Resource的对象表示。第二个规则,就是将节点的相应属性进行设置,包括可以能够识别的属性和通过setProperties设置的其他属性。第三个规则则是将这个对象添加到context下的namingresources集合中。

通过对以上代码的了解,我们知道如果不是标准的xml节点,那么tomcat在解析中是不会解析的。因此,没有相应的解析规则可以匹配。那么,tomcat如何进一步解析本文中的resource节点,并加入到jndi中,则是下一篇文章则要分析的了。

转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/201208080002.html

相关文章:

作者: flym

I am flym,the master of the site:)

发表评论

邮箱地址不会被公开。 必填项已用*标注