• 【Tomcat8源码学习之五】Digester


    Tomcat源码版本:apache-tomcat-8.5.54-src
    JDK源码版本:jdk1.8.0_171

    org.apache.tomcat.util.digester.Digester用于解析server.xml,通过它可以很方便的从xml文件生成java对象。
    1、Java解析XML文件主要有两个方式
    (1)预加载DOM树,代表是java官方的JDOM解析和社区的DOM4J解析,DOM4J更好用;
    (2)事件机制的SAX,代表就是SAXReader,该方法思路是一行一行的读取XML文件,没遇到一个节点,就看看有没有监听该事件的监听器,如果有就触发;
    Digester底层采用SAX(Simple API for XML)解析XML文件,所以对象转换由"事件"驱动,在遍历每个节点时,检查是否有匹配模式,如果有,则执行规则定义的操作,比如创建特定的Java对象,或调用特定对象的方法等。此处的XML元素根据匹配模式(matching pattern)识别,而相关操作由规则(rule)定义。

    2、tomcat使用digester解析server.xml代码流程

    Catalina.java::load()

    //用digester解析server.xml文件,把配置文件中的配置解析成java对象
    //1.准备好用来解析server.xml文件需要用的digester。
    Digester digester = createStartDigester();
    //2.server.xml文件作为一个输入流传入
    File file = configFile();
    InputStream inputStream = new FileInputStream(file);
    //3.使用inputStream构造一个sax的inputSource
    InputSource inputSource = new InputSource(file.toURI().toURL().toString());
    inputSource.setByteStream(inputStream);
    //4.把当前类压入到digester的栈顶,用来作为digester解析出来的对象的一种引用
    digester.push(this);
    //5.调用digester的parse()方法进行解析。
    digester.parse(inputSource);

    3、设置规则-createStartDigester()方法

    protected Digester createStartDigester() {
            long t1=System.currentTimeMillis();
            // 实例化一个Digester对象
            Digester digester = new Digester();
            // 设置为false表示解析xml时不需要进行DTD的规则校验  
            digester.setValidating(false);
            // 是否进行节点设置规则校验,如果xml中相应节点没有设置解析规则会在控制台显示提示信息  
            digester.setRulesValidation(true);
            // 将xml节点中的className作为假属性,不必调用默认的setter方法(一般的节点属性在解析时将会以属性值作为入参调用该节点相应对象的setter方法,而className属性的作用是提示解析器用该属性的值来实例化对象)
            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);
    
            // addObjectCreate方法的意思是碰到xml文件中的Server节点则创建一个StandardServer对象 
            digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");
            // 根据Server节点中的属性信息调用相应属性的setter方法,还会调用setPort、setShutdown方法,入参分别是8005、SHUTDOWN  
            digester.addSetProperties("Server");
            // 将Server节点对应的对象作为入参调用栈顶对象的setServer方法,这里的栈顶对象即下面的digester.push方法所设置的当前类的对象this,就是说调用MyDigester类的setMyServer方法
            digester.addSetNext("Server","setServer","org.apache.catalina.Server");
            
            // 碰到xml的Server节点下的Listener节点时取className属性的值作为实例化类实例化一个对象 
            //GlobalNamingResources 全局J2EE企业命名上下文
            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 按照className配置来创建  生命周期监听器
            //第二个参数 MUST be specified in the element
            digester.addObjectCreate("Server/Listener",null,"className");
            digester.addSetProperties("Server/Listener");
            digester.addSetNext("Server/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");
            //StandardService
            digester.addObjectCreate("Server/Service","org.apache.catalina.core.StandardService","className");
            digester.addSetProperties("Server/Service");
            digester.addSetNext("Server/Service","addService","org.apache.catalina.Service");
            //Service/Listener 按照className配置来创建
            digester.addObjectCreate("Server/Service/Listener",null, "className");
            digester.addSetProperties("Server/Service/Listener");
            digester.addSetNext("Server/Service/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");
            //StandardThreadExecutor
            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");
            //Connector
            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");
            //SSLHostConfig
            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");
            //Certificate
            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");
            //OpenSSLConf
            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");
            //OpenSSLConfCmd
            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");
            //Server/Service/Connector/Listener
            digester.addObjectCreate("Server/Service/Connector/Listener",null,"className");
            digester.addSetProperties("Server/Service/Connector/Listener");
            digester.addSetNext("Server/Service/Connector/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");
            //UpgradeProtocol 升级协议
            digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",null,"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;
        }

    4、解析动作-parse

    org.apache.tomcat.util.Digester::parse(inputSource);
    com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser::parse
    com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser::parse
    com.sun.org.apache.xerces.internal.parsers.XMLParser::parse
    com.sun.org.apache.xerces.internal.parsers.XIncludeAwareParserConfiguration::parse
    com.sun.org.apache.xerces.internal.parsers.XML11Configuration::parse
    com.sun.org.apache.xerces.internal.impl.XMLVersionDetector::startDocumentParsing  //设置属性编码
    org.apache.tomcat.util.Digester::startDocument
    com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl::scanDocument //解析整个文档
    com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl::next
    com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$ContentDriver::scanRootElementHook
    com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl::scanStartElement
    com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator::startElement
    com.sun.org.apache.xerces.internal.parsersAbstractSAXParser::startElement
    org.apache.tomcat.util.Digester::startElement

    开始调用startElement对元素开始解析,先拼接模式然后获取其对应的规则,遍历所有规则,调用其对应规则实例的begin方法,这要求所有规则实现抽象类Rule,规则的添加在上文解析过程中。

    参考:
    Tomcat组件梳理—Digester的使用

  • 相关阅读:
    PhpStorm 常用快捷键和配置+关闭快捷键ctrl+alt+方向键旋转屏幕+快速复制一行快捷键恢复
    WP七牛云插件详解
    注册表删除键值时拒绝访问
    删除注册表子项清除u盘使用痕迹
    一件代发发货人怎么写?淘宝代理发货流程
    联动设置
    使用vue实现行列转换的一种方法。
    从后端到前端之Vue(五)小试路由
    从后端到前端之Vue(四)小试牛刀——真实项目的应用(树、tab、数据列表和分页)
    从后端到前端之Vue(三)小结以及一颗真实的大树
  • 原文地址:https://www.cnblogs.com/cac2020/p/12763164.html
Copyright © 2020-2023  润新知