2019-10-28 17:44  阅读(2142)
文章分类:Tomcat 源码分析 文章标签:TomcatTomcat 源码
©  原文作者:clawhub 原文地址:http://clawhub.club

在执行catalina的load方法时,会执行配置Digester、读取配置文件、将Catalina作为digester的顶级容器、digester解析配置文件并注入各个组件。
简略修改了一下代码:

        // Create and execute our Digester
        //创建和配置将用于启动的Digester。
        //配置解析server.xml中各个标签的解析类
        Digester digester = createStartDigester();
    
        //下面一大段都是为了conf/server.xml配置文件,失败就加载server-embed.xml
        File file  = configFile();
        InputSource inputStream = new FileInputStream(file);
        InputSource inputSource = new InputSource(file.toURI().toURL().toString());
        inputSource.setByteStream(inputStream);
    
        //把Catalina作为一个顶级容器
        digester.push(this);
        //解析过程会实例化各个组件,比如Server、Container、Connector等
        digester.parse(inputSource);
    

Digeter是apache的common项目,作用是将XML转化成对象,使用者直接从对象中获取xml的节点信息。
Digester是对SAX的包装,它也是基于文件流来解析xml文件,只不过这些解析操作对用户是透明的。
在分析createStartDigester之前很有必要贴一下server.xml配置:

        <?xml version="1.0" encoding="UTF-8"?>
        <Server port="8005" shutdown="SHUTDOWN">
          <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
          <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
          <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
          <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
          <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
          <GlobalNamingResources>
            <Resource name="UserDatabase" auth="Container"
                      type="org.apache.catalina.UserDatabase"
                      description="User database that can be updated and saved"
                      factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
                      pathname="conf/tomcat-users.xml" />
          </GlobalNamingResources>
          <Service name="Catalina">
            <Connector port="8080" protocol="HTTP/1.1"
                       connectionTimeout="20000"
                       redirectPort="8443" />
            <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
            <Engine name="Catalina" defaultHost="localhost">
              <Realm className="org.apache.catalina.realm.LockOutRealm">
                <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                       resourceName="UserDatabase"/>
              </Realm>
              <Host name="localhost"  appBase="webapps"
                    unpackWARs="true" autoDeploy="true">
                <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                       prefix="localhost_access_log" suffix=".txt"
                       pattern="%h %l %u %t "%r" %s %b" />
              </Host>
            </Engine>
          </Service>
        </Server>
    

这个是默认配置,我将注释之类去除了。

createStartDigester

        /**
             * 创建和配置将用于启动的Digester。
             *
             * @return the main digester to parse server.xml
             */
            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> attrs = new ArrayList<>();
                attrs.add("className");
                fakeAttributes.put(Object.class, attrs);
                //设置假属性。
                digester.setFakeAttributes(fakeAttributes);
                //确定是否使用上下文类加载器来解析/加载在各种规则中定义的类。
                digester.setUseContextClassLoader(true);
    
                // 配置我们将使用的操作
                //addObjectCreate:为指定的参数添加“对象创建”规则。
                digester.addObjectCreate("Server",
                        "org.apache.catalina.core.StandardServer",
                        "className");
                //为指定的参数添加“设置属性”规则。
                digester.addSetProperties("Server");
                //为指定的参数添加“set next”规则。
                digester.addSetNext("Server",
                        "setServer",
                        "org.apache.catalina.Server");
    
                // StandardServer.GlobalNamingResources
                digester.addObjectCreate("Server/GlobalNamingResources",
                        "org.apache.catalina.deploy.NamingResourcesImpl");
                digester.addSetProperties("Server/GlobalNamingResources");
                digester.addSetNext("Server/GlobalNamingResources",
                        "setGlobalNamingResources",
                        "org.apache.catalina.deploy.NamingResourcesImpl");
    
                //StandardServer.addLifecycleListener
                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");
    
                //StandardServer.addService:StandardService
                digester.addObjectCreate("Server/Service",
                        "org.apache.catalina.core.StandardService",
                        "className");
                digester.addSetProperties("Server/Service");
                digester.addSetNext("Server/Service",
                        "addService",
                        "org.apache.catalina.Service");
    
                //StandardService.addLifecycleListener
                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");
    
                //Executor
                //StandardService.addExecutor
                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");
    
                //StandardService.addConnector
                digester.addRule("Server/Service/Connector",
                        new ConnectorCreateRule());
                digester.addRule("Server/Service/Connector", new SetAllPropertiesRule(
                        new String[]{"executor", "sslImplementationName", "protocol"}));
                digester.addSetNext("Server/Service/Connector",
                        "addConnector",
                        "org.apache.catalina.connector.Connector");
    
                //Connector.addSslHostConfig
                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");
    
                //SSLHostConfig.addCertificate
                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");
    
                //SSLHostConfig.setOpenSslConf
                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.addCmd
                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");
    
                //Connector.addLifecycleListener
                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");
    
                //Connector.addUpgradeProtocol
                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;
    
            }
    

先简单介绍一下Digester方法:

  • addObjectCreate
    创建对象
  • addSetProperties
    设置属性
  • addSetNext
    创建对象之间关系
  • addRule
    该方法会将一个Rule对象和它所匹配的模式添加到Digester对象的Rules集合中
  • addRuleSet
    调用addRuleInstances来解析xml标签

上述所有的步骤都是为了解析XML而准备,解析时根据XML内各标签的包含关系来创建对象,设置属性,关联对象。
备注:当前栈顶元素为Catalina实例。
下面简单看几个标签的解析规则:

Server

          //addObjectCreate:为指定的参数添加“对象创建”规则。
                digester.addObjectCreate("Server",
                        "org.apache.catalina.core.StandardServer",
                        "className");
                //为指定的参数添加“设置属性”规则。
                digester.addSetProperties("Server");
                //为指定的参数添加“set next”规则。
                digester.addSetNext("Server",
                        "setServer",
                        "org.apache.catalina.Server");
    

创建StandardServer实例对象,这是属性,调用上一个元素Catalina的setServer方法。
现在栈顶元素为StandardServer实例对象,也就是Server的外层元素是Catalina。

        public void setServer(Server server) {
                this.server = server;
            }
    

Service

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

会先创建StandardService实例,属性填充,并找到上层标签Server的实例StandardServer,执行addService方法。

         @Override
            public void addService(Service service) {
                //service持有Server的引用
                service.setServer(this);
                //服务锁,即service要一个一个的加入
                synchronized (servicesLock) {
                    //services数组拷贝,将新来的service增加到最后
                    Service results[] = new Service[services.length + 1];
                    System.arraycopy(services, 0, results, 0, services.length);
                    results[services.length] = service;
                    services = results;
                    //当前Server组件是available
                    if (getState().isAvailable()) {
                        try {
                            //调用service的生命周期方法start
                            service.start();
                        } catch (LifecycleException e) {
                            // Ignore
                        }
                    }
                    // Report this property change to interested listeners
                    //将此属性更改报告给感兴趣的侦听器
                    support.firePropertyChange("service", null, service);
                }
            }
    

可以看出Server与Service是一对多的关系。

Connector

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

这里是通过ConnectorCreateRule来解析Connector节点,ConnectorCreateRule实现了Rule接口,解析的时候先执行begin方法,获取
digester的上层元素Service的实例StandardService,再创建Connector实例,设置一些属性之后将Connector入digester栈。解析结束后
调用end方法,将Connector实例出栈。也就是说当前栈顶是Service实例,执行StandardService的addConnector方法建立联系。

         public void addConnector(Connector connector) {
                //connector一个一个加入到当前Service组件中
                synchronized (connectorsLock) {
                    connector.setService(this);
                    Connector results[] = new Connector[connectors.length + 1];
                    System.arraycopy(connectors, 0, results, 0, connectors.length);
                    results[connectors.length] = connector;
                    connectors = results;
                    if (getState().isAvailable()) {
                        try {
                            //生命周期函数
                            connector.start();
                        } catch (LifecycleException e) {
                            log.error(sm.getString(
                                    "standardService.connector.startFailed",
                                    connector), e);
                        }
                    }
                    // Report this property change to interested listeners
                    support.firePropertyChange("connector", null, connector);
                }
            }
    

从这可以看出Service组件与Connector组件是一对多的关系。

Engine

         digester.addRuleSet(new EngineRuleSet("Server/Service/"));
    

EngineRuleSet实现了RuleSet接口,当解析xml时会调用addRuleInstances方法:

         public void addRuleInstances(Digester digester) {
    
                digester.addObjectCreate(prefix + "Engine",
                                         "org.apache.catalina.core.StandardEngine",
                                         "className");
                digester.addSetProperties(prefix + "Engine");
                digester.addRule(prefix + "Engine",
                                 new LifecycleListenerRule
                                 ("org.apache.catalina.startup.EngineConfig",
                                  "engineConfigClass"));
                digester.addSetNext(prefix + "Engine",
                                    "setContainer",
                                    "org.apache.catalina.Engine");
    
                //Cluster configuration start
                digester.addObjectCreate(prefix + "Engine/Cluster",
                                         null, // MUST be specified in the element
                                         "className");
                digester.addSetProperties(prefix + "Engine/Cluster");
                digester.addSetNext(prefix + "Engine/Cluster",
                                    "setCluster",
                                    "org.apache.catalina.Cluster");
                //Cluster configuration end
    
                digester.addObjectCreate(prefix + "Engine/Listener",
                                         null, // MUST be specified in the element
                                         "className");
                digester.addSetProperties(prefix + "Engine/Listener");
                digester.addSetNext(prefix + "Engine/Listener",
                                    "addLifecycleListener",
                                    "org.apache.catalina.LifecycleListener");
    
                digester.addRuleSet(new RealmRuleSet(prefix + "Engine/"));
    
                digester.addObjectCreate(prefix + "Engine/Valve",
                                         null, // MUST be specified in the element
                                         "className");
                digester.addSetProperties(prefix + "Engine/Valve");
                digester.addSetNext(prefix + "Engine/Valve",
                                    "addValve",
                                    "org.apache.catalina.Valve");
            }
    

套路还是一样的,先解析一层,之后再返回上一层。最终会执行到StandardService的setContainer方法:

         public void setContainer(Engine engine) {
                //废掉老的Engine
                Engine oldEngine = this.engine;
                if (oldEngine != null) {
                    oldEngine.setService(null);
                }
                //绑定新的engine
                this.engine = engine;
                if (this.engine != null) {
                    this.engine.setService(this);
                }
                if (getState().isAvailable()) {
                    if (this.engine != null) {
                        try {
                            //生命周期函数
                            this.engine.start();
                        } catch (LifecycleException e) {
                            log.warn(sm.getString("standardService.engine.startFailed"), e);
                        }
                    }
                    // Restart MapperListener to pick up new engine.
                    //重启MapperListener以获取新引擎。
                    try {
                        mapperListener.stop();
                    } catch (LifecycleException e) {
                        log.warn(sm.getString("standardService.mapperListener.stopFailed"), e);
                    }
                    try {
                        mapperListener.start();
                    } catch (LifecycleException e) {
                        log.warn(sm.getString("standardService.mapperListener.startFailed"), e);
                    }
                    //关闭老的引擎
                    if (oldEngine != null) {
                        try {
                            oldEngine.stop();
                        } catch (LifecycleException e) {
                            log.warn(sm.getString("standardService.engine.stopFailed"), e);
                        }
                    }
                }
    
                // Report this property change to interested listeners
                support.firePropertyChange("container", oldEngine, this.engine);
            }
    

可以看出Service与Engine引擎是一对一的关系。

Host

        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
    

能看出来Host在Engine的下一层。最终会执行StandardEngine的addChild方法,将Host容器置于Engine内部。

Context

        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
    

Context在Host的下一层,也会执行StandardHost的addChild方法,将Context容器置于Host容器内部。

发现没,这里没涉及到Wrapper容器,它是什么时候产生的呢?
这里先保留,等后面遇到再说。

至此,server.xml配置文件的解析差不多就了解了,也知道了Catalina中的Server组件是怎么注入的,还了解了Server、Service、Engine、Host、Context之间的关系。


来源:https://www.jianshu.com/u/9632919f32c3

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Tomcat源码分析【五】启动过程分析之配置文件解析与组件注入
上一篇
Tomcat源码分析【四】启动过程分析之主干流程
下一篇
Tomcat源码分析【六】启动过程分析之生命周期方法init