前阵子,准备重新测试一下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