02. Tomcat源代码—05.主要的类-02.Digester

1. 介绍

digester最初是struct的一个工具模块,功能是解析xml,后来分离出来形成commons-digester工具类库。

digester底层是基于SAX、事件驱动、栈的方式来搭建实现的:

  1. SAX,用于解析xml
  2. 事件驱动,在SAX解析的过程中加入事件来支持我们的对象映射
  3. 栈,在解析xml元素的开始和结束时,需要通过xml元素映射的类对象的入栈、出栈来完成事件的调用

下面给个简单示例及解释:

<dependency>
    <groupId>commons-digester</groupId>
    <artifactId>commons-digester</artifactId>
    <version>2.1</version>
</dependency>
public class Foo {
    private List<Bar> bars = new ArrayList<>();

    public void addBar(Bar bar) {
        bars.add(bar);
    }

    @Override
    public String toString() {
        return "Foo{" +
                "bars=" + bars +
                '}';
    }
}

public class Bar {
    int id;
    String title;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String toString() {
        return "Bar{" +
                "id=" + id +
                ", title='" + title + '\'' +
                '}';
    }
}
<foo name="the Parent">
    <bar id="123" title="the first Child"></bar>
    <bar id="456" title="the second Child"></bar>
</foo>

注意:下面调用的digester各个方法,只是解释XML的层级节点关系,跟每层相同节点的个数没有关系,如上面xml中,bar有两个,但下面规则中只需要设置1次。

public class DigestTest {
    public static void main(String[] args) throws IOException, SAXException {
        File file = new File("D:/foo.xml");
        InputStream inputStream = new FileInputStream(file);
        InputSource inputSource = new InputSource(file.toURI().toURL().toString());
        inputSource.setByteStream(inputStream);

        Digester digester = new Digester();
        // 不进行XML与相应的DTD合法性验证
        digester.setValidating(false);
        // 当遇到<foo>时创建一个digester.Foo对象,并将其放在栈顶
        digester.addObjectCreate("foo", "digester.Foo");
        // 根据<foo>元素的属性,name="the Parent",对刚创建的Foo对象属性进行设置
        digester.addSetProperties("foo");
        // 当遇到子元素<bar>时,创建一个digester.Bar对象,并将其放在栈顶
        digester.addObjectCreate("foo/bar", "digester.Bar");
        // 根据<bar>元素的属性,id="123" title="the first child",对刚创建的Bar对象属性进行设置
        digester.addSetProperties("foo/bar");
        // 对这个bar节点,调用其父节点foo的addBar方法,该方法参数类型为digeseter.Bar
        digester.addSetNext("foo/bar", "addBar", "digester.Bar");

        Foo foo = (Foo) digester.parse(inputSource);
        System.out.println(foo);
    }

}

运行结果为:
DigesterTest运行结果
重点介绍下几个方法:

  1. Digester.addObjectCreate(String pattern, String className, String attributeName)
    pattern:匹配的节点
    className:该节点对应的默认实体类
    attributeName:如果该节点有className属性, 用className的值替换默认实体类
    如:
    <foo className = "digest.Foo"></foo>
    Digester.addObjectCreate("foo", Foo1.class.getName, "className");
    上面在xml中foo节点className是digester.Foo,会创建digester.Foo的实例替换Foo1.class.getName的实例;如果xml中foo节点没有className属性,会创建Foo1.class.getName的实例

  2. digester.addSetProperties(“XXX”);
    将指定节点的属性映射到对象中。
    如:
    <bar id="123" title="the Child"></bar>
    digester.addSetProperties("foo/bar");
    上面会将xml中bar节点的id、title属性映射到创建的Bar对象实例的id、name属性中。

  3. Digester.addSetNext(String pattern, String methodName, String paramType)
    pattern:匹配的节点
    methodName:调用父节点的方法
    paramType:父节点的方法接收的参数类型
    如:

<foo name="the Parent">
    <bar id="123" title="the Child"></bar>
</foo>

digester.addSetNext("foo/bar", "addBar", "digester.Bar");
匹配到xml中bar节点,调用其父节点foo的方法addBar,这个方法的参数类型是digester.Bar。

public void addRule(String pattern, Rule rule) // 当匹配到pattern模式时,增加一个自定义规则
public void addRuleSet(RuleSet ruleSet) // 增加规则集,一个规则集指的是对一个节点及下面的所有后续节点(子节点、子节点的子节点...)的解析

2. Tomcat中server.xml解析

下面再看Tomcat中server.xml的解析,就很容易了。
Catalina.createStartDigester():

protected Digester createStartDigester() {
    long t1 = System.currentTimeMillis();
    // Initialize the digester
    Digester digester = new Digester();
    digester.setValidating(false);
    digester.setRulesValidation(true);

    // 设置无效属性
    Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
    List<String> objectAttrs = new ArrayList<>();
    objectAttrs.add("className");
    fakeAttributes.put(Object.class, objectAttrs);
    // Ignore attribute added by Eclipse for its internal tracking
    List<String> contextAttrs = new ArrayList<>();
    contextAttrs.add("source");
    fakeAttributes.put(StandardContext.class, contextAttrs);
    digester.setFakeAttributes(fakeAttributes);

    // 设置是否使用线程上下文类加载器
    digester.setUseContextClassLoader(true);

    // Configure the actions we will be using
    // Server
    digester.addObjectCreate("Server",
            "org.apache.catalina.core.StandardServer",
            "className");
    digester.addSetProperties("Server");
    digester.addSetNext("Server",
            "setServer",
            "org.apache.catalina.Server");
	
	// Server/GlobalNamingResources
    digester.addObjectCreate("Server/GlobalNamingResources",
            "org.apache.catalina.deploy.NamingResourcesImpl");
    digester.addSetProperties("Server/GlobalNamingResources");
    digester.addSetNext("Server/GlobalNamingResources",
            "setGlobalNamingResources",
            "org.apache.catalina.deploy.NamingResourcesImpl");

	// Server/Listener
    digester.addObjectCreate("Server/Listener",
            null, // MUST be specified in the element
            "className");
    digester.addSetProperties("Server/Listener");
    digester.addSetNext("Server/Listener",
            "addLifecycleListener",
            "org.apache.catalina.LifecycleListener");

	// Server/Service
    digester.addObjectCreate("Server/Service",
            "org.apache.catalina.core.StandardService",
            "className");
    digester.addSetProperties("Server/Service");
    digester.addSetNext("Server/Service",
            "addService",
            "org.apache.catalina.Service");

	// Server/Service/Listener
    digester.addObjectCreate("Server/Service/Listener",
            null, // MUST be specified in the element
            "className");
    digester.addSetProperties("Server/Service/Listener");
    digester.addSetNext("Server/Service/Listener",
            "addLifecycleListener",
            "org.apache.catalina.LifecycleListener");

    // Server/Service/Executor
    digester.addObjectCreate("Server/Service/Executor",
            "org.apache.catalina.core.StandardThreadExecutor",
            "className");
    digester.addSetProperties("Server/Service/Executor");
    digester.addSetNext("Server/Service/Executor",
            "addExecutor",
            "org.apache.catalina.Executor");


    digester.addRule("Server/Service/Connector",
            new ConnectorCreateRule());
    digester.addRule("Server/Service/Connector",
            new SetAllPropertiesRule(new String[]{"executor", "sslImplementationName"}));
    digester.addSetNext("Server/Service/Connector",
            "addConnector",
            "org.apache.catalina.connector.Connector");

    digester.addObjectCreate("Server/Service/Connector/SSLHostConfig",
            "org.apache.tomcat.util.net.SSLHostConfig");
    digester.addSetProperties("Server/Service/Connector/SSLHostConfig");
    digester.addSetNext("Server/Service/Connector/SSLHostConfig",
            "addSslHostConfig",
            "org.apache.tomcat.util.net.SSLHostConfig");

    digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
            new CertificateCreateRule());
    digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
            new SetAllPropertiesRule(new String[]{"type"}));
    digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate",
            "addCertificate",
            "org.apache.tomcat.util.net.SSLHostConfigCertificate");

    digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
            "org.apache.tomcat.util.net.openssl.OpenSSLConf");
    digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf");
    digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
            "setOpenSslConf",
            "org.apache.tomcat.util.net.openssl.OpenSSLConf");

    digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
            "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
    digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd");
    digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
            "addCmd",
            "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");

    digester.addObjectCreate("Server/Service/Connector/Listener",
            null, // MUST be specified in the element
            "className");
    digester.addSetProperties("Server/Service/Connector/Listener");
    digester.addSetNext("Server/Service/Connector/Listener",
            "addLifecycleListener",
            "org.apache.catalina.LifecycleListener");

    digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",
            null, // MUST be specified in the element
            "className");
    digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");
    digester.addSetNext("Server/Service/Connector/UpgradeProtocol",
            "addUpgradeProtocol",
            "org.apache.coyote.UpgradeProtocol");

    // Add RuleSets for nested elements
    digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
    digester.addRuleSet(new EngineRuleSet("Server/Service/"));
    digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
    digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
    addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
    digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));

    // When the 'engine' is found, set the parentClassLoader.
    digester.addRule("Server/Service/Engine",
            new SetParentClassLoaderRule(parentClassLoader));
    addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");

    long t2 = System.currentTimeMillis();
    if (log.isDebugEnabled()) {
        log.debug("Digester for server.xml created " + (t2 - t1));
    }
    return digester;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值