Tomcat(三)Tomcat配置文件Server.xml解析

一 核心的解析逻辑

Tomcat核心解析图

  • Catalina的load方法中,完成了server.xml的解析,将server.xml配置的Server、Service、Connector、Engine、Host各组件实例化,并维护父子级关系。

1.1 parseServerXml


核心的解析逻辑就在上图38~49行:

Digester digester = start ? createStartDigester() : createStopDigester();
InputStream inputStream = resource.getInputStream();
InputSource inputSource = new InputSource(resource.getURI().toURL().toString());
inputSource.setByteStream(inputStream);
digester.push(this);
digester.parse(inputSource);
  • 创建一个 Digester对象,将当前对象压入Digester 里的对象栈顶,根据 inputSource里对应的文件xml路径及所创建的Digester对象所包含的解析规则生成相应对象,并调用相应方法将对象之间关联起来。这里我们引入一个新的概念Digester,Digester就是用来解析xml的。

二 XML文件解析方法

  • Java解析XML文件主要存在两种方式:预加载DOM树及事件机制的SAX。

2.1 预加载DOM树

  • 将整个XML文件读取到内存中,在内容中构造一个DOM树,然后java代码只需要操作这个树就可以。该方法的主要实现为DOM解析,在此基础上有两个扩展:JDOM解析,DOM4J解析,DOM4J更常用一些。
    • 优点:使用DOM时,XML文档的结构在内存中很清晰,元素与元素之间的关系保留了下来,即能记录文档的所有信息
    • 缺点:如果XML文档非常大,把整个XML文档装在进内存容易造成内容溢出,无法加载了

2.2 事件机制的SAX

  • 一行一行的读取XML文件,每遇到一个节点,就看看有没有监听该事件的监听器,如果有就触发。当XML文件读取结束后,内存里不会保存任何数据,整个XML的解析就结束了。所以,这里面最重要的是对感兴趣的节点进行监听和处理。
    • 优点:使用SAX不会占用大量内存来保存XML文档数据,效率高
    • 缺点:不像DOM一样将文档树长期留驻在内存,数据不是长久的。事件过后,若没保存数据,那么数据就会丢失

三 Digester

3.1 Digester基本架构

Digester基本架构图

  • DefaultHandler2:来自SAX,Digester继承该类,说明Digester底层用的是SAX
  • Digester:Digester解析的核心类和入口类,客户端(需要解析xml的调用方)需要实例化该类,设置该类,并调用该类的方法
  • Rules:保存XML的节点和规则的映射关系,默认实现类是RulesBase
  • RuesBase:是Rules的默认实现类。当有一个XML节点开始解析时,会在这里面找是否有对应的节点,并根据节点查找对应的处理规则
  • Rule:节点的处理方法,内置的或者自定义的规则都是继承自该接口

3.2 Digester解析XML文档的流程

  1. Client需要创建一个Digester对象
  2. Client必须根据自己的XML格式来添加所有的Rule
  3. Client调用Digester的parse操作来解析XML文件。
  4. Digester实现了SAX的接口,解析时遇到具体的XML对象时会调用startElement(继承自DefaultHandler2)等方法
  • 在这些SAX接口函数中,会扫描规则链(RulesBase),找到匹配规则,规则匹配一般都是根据具体的元素名称来进行匹配
  • 找到对应的Rule后,依次执行Rule
    文档结束后,会执行所有Rule的finish函数

3.3 使用流程

Digester digester = createStartDigester();
File file = configFile();
InputStream inputStream = new FileInputStream(file);
InputSource inputSource = new InputSource(file.toURI().toURL().toString());
inputSource.setByteStream(inputStream);
digester.push(this);
digester.parse(inputSource);
  1. 准备用来解析server.xml文件需要用的digester
  2. 读取server.xml文件作为一个输入流
  3. 使用inputStream构造一个sax的inputSource,因为digester底层用的是sax去解析的
  4. 把当前类压入到digester的栈顶,用来作为digester解析出来的对象的一种引用,digester自带一个栈的结构
  5. 调用digester的parse()方法进行解析。前面几步都是在准备环境,这里才是正真的去解析了

四 Digeste使用总结

Degister总体上,我们可以将其方法分为两类:操作类和规则类。

  • 操作类
    • void setValidating(boolean validating):是否根据DTD校验XML
    • void push(Object object):将对象压入栈
    • Object peek():获取栈顶对象
    • Object pop():弹出栈顶对象
    • Object parse(InputSource input):解析输入源
  • 规则类
    • void addObjectCreate(String pattern, String className, String attributeName):增加对象创建规则,当匹配到pattern模式时,如果指定了attributeName,则根据attributeName创建类对象;否则根据className创建类对象
    • void addSetProperties(String pattern):增加属性设置规则,当匹配到pattern模式时,就填充其属性
      void addSetNext(String pattern, String methodName, String paramType):增加设置下一个规则,当匹配到pattern模式时,调用父节点的methodName方法,paramType为方法传入参数的类型
      void addRule(String pattern, Rule rule):当匹配到pattern模式时,增加一个自定义规则
    • void addRuleSet(RuleSet ruleSet):增加规则集,一个规则集指的是对一个节点及下面的所有子节点(子节点、子节点的子节点…)的解析

五 Tomcat server.xml解析

5.1 Degister创建

protected Digester createStartDigester() {
   // Initialize the digester
   Digester digester = new Digester();
   digester.setValidating(false);   digester.setRulesValidation(true);
   Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
   // Ignore className on all elements
   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);
   // Ignore Connector attribute used internally but set on Server
   List<String> connectorAttrs = new ArrayList<>();   connectorAttrs.add("portOffset");   fakeAttributes.put(Connector.class, connectorAttrs);   digester.setFakeAttributes(fakeAttributes);   digester.setUseContextClassLoader(true); 
   // Configure the actions we will be using
   digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer", "className");    digester.addSetProperties("Server");
   digester.addSetNext("Server","setServer", "org.apache.catalina.Server");    digester.addObjectCreate("Server/GlobalNamingResources","org.apache.catalina.deploy.NamingResourcesImpl");   digester.addSetProperties("Server/GlobalNamingResources");   digester.addSetNext("Server/GlobalNamingResources",   "setGlobalNamingResources",                     "org.apache.catalina.deploy.NamingResourcesImpl");
   digester.addRule("Server/Listener",new ListenerCreateRule(null, "className"));
   digester.addSetProperties("Server/Listener");
   digester.addSetNext("Server/Listener","addLifecycleListener",                      "org.apache.catalina.LifecycleListener");
   digester.addObjectCreate("Server/Service","org.apache.catalina.core.StandardService",   "className");
   digester.addSetProperties("Server/Service");
   digester.addSetNext("Server/Service","addService","org.apache.catalina.Service");
   digester.addObjectCreate("Server/Service/Listener",null,"className");
   digester.addSetProperties("Server/Service/Listener");
   digester.addSetNext("Server/Service/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener"); 
   //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.addSetProperties("Server/Service/Connector", new String[]{"executor","sslImplementationName", "protocol"});
   digester.addSetNext("Server/Service/Connector","addConnector","org.apache.catalina.connector.Connector");
   digester.addRule("Server/Service/Connector", new AddPortOffsetRule());
   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.addSetProperties("Server/Service/Connector/SSLHostConfig/Certificate", 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,"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,"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/"); 
   return digester;
}   

5.3 Server解析

5.3.1 创建Server实例

digester.addObjectCreate("Server",                         "org.apache.catalina.core.StandardServer","className");
digester.addSetProperties("Server");
digester.addSetNext("Server","setServer","org.apache.catalina.Server");

创建StandardServer对象,设置其对象的属性,调用父节点Catalina的setServer方法将Server添加到Catalina中。

5.3.2 为Server添加全局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中。

5.3.4 为Server添加生命周期监听器

digester.addRule("Server/Listener",
        new ListenerCreateRule(null, "className"));
digester.addSetProperties("Server/Listener");
digester.addSetNext("Server/Listener",             "addLifecycleListener",                    "org.apache.catalina.LifecycleListener");

当匹配到”Server/Listener”节点,使用ListenerCreateRule解析。注意ListenerCreateRule第一个参数是className,即默认类名,为null。所以Listener不会有默认值类型。因为Listener本来就是自定义的。
比如在server.xml中,为Server添加如下监听器:

<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener" />
-->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  • VersionLoggerListener:在Server初始化之前打印操作系统,JVM以及服务器的版本信息
  • AprLifecycleListener:在Server初始化之前加载APR库,并于Server停止之后销毁
  • JreMemoryLeakPreventionListener:在Server初始化之前调用,以解决单例对象创建导致的JVM内存泄漏问题以及锁文件问题
  • GlobalResourcesLifecycleListener:在Server启动时,将JNDI资源注册为MBean进行管理
  • ThreadLocalLeakPreventionListener:用于在Context停止时重建Exceutor池中的线程,避免导致内存泄漏

5.4 Servive解析

5.4.1 创建Service实例

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

创建StandardService实例,调用StandardService实例的set方法设置属性,最后调用父节点Server的addService方法,将service添加到Server。

5.4.2 为Service添加生命周期监听器

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");

这里创建生命周期监听器,className上送值为null,所以不存在默认类型,比如有”Server/Service/Listener”节点的className指定类型。
随后调用父节点Service的addLifecycleListener方法,将监听器添加到Service。

5.5 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");

创建StandardThreadExecutor实例,并调用父节点Service的addExecutor方法添加到Service。通过该配置我们可以知道,Tomcat共享Excetor的级别为Service,Catalina默认情况下未配置Executor,即不共享。

5.6 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");

创建Connector实例,并调用父组建Service的addConnector方法添加到Service。设置相关属性时,将executor和sslImplementationName属性排除,因为在Connector创建时,会判断当前是否指定了executor属性,如果是,则从Service中查找该名称的executor并设置到Connector中。同样,Connector创建时,也会判断是否添加了sslIlplementationName属性,如果是,则将属性值设置到使用的协议中,为其指定一个SSL实现。

5.6.1 为Connector添加虚拟主机SSL配置

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");

5.6.2 为Connector添加生命周期监听器

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");

5.6.3 为Connector添加升级协议

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");

用于支持HTTP/2。

5.7 容器组件解析

// 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/"));

此部分指定了Servlet容器相关的各级嵌套子节点的解析规则,而且没类嵌套子节点的解析规则封装为一个RuleSet,包括GlobalNamingResources,Engine,Host,Context以及Cluster解析。

5.7.1 Engine解析

Engine解析是在digester.addRuleSet(new EngineRuleSet(“Server/Service/”));方法中完成的。最终EngineRuleSet的addRuleInstances会生效,将规则添加到Digester,如下所示:

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");
}

可以看到,该方法中完成了如下几项工作:

  • 创建实例,并通过setContainer添加Service中
  • 为Engine添加了一个生命周期的监听器EngineConfig,这个监听器是代码里写死,不是通过server.xml配置的
  • 为Engine添加集群配置
  • 为Engine添加生命周期监听器,这里的监听器是server.xml文件中配置的
    为Engine添加Valve,具体的拦截器由className属性指定,不指定默认值

5.7.2 Host的解析

Host的解析是在digester.addRuleSet(new HostRuleSet(“Server/Service/Engine/”));方法中完成的。最终HostRuleSet的addRuleInstances会生效,将规则添加到Digester,如下所示:

public void addRuleInstances(Digester digester) {
    
    digester.addObjectCreate(prefix + "Host",
                             "org.apache.catalina.core.StandardHost",
                             "className");
    digester.addSetProperties(prefix + "Host");
    digester.addRule(prefix + "Host",
                     new CopyParentClassLoaderRule());
    digester.addRule(prefix + "Host",
                     new LifecycleListenerRule
                     ("org.apache.catalina.startup.HostConfig",
                      "hostConfigClass"));
    digester.addSetNext(prefix + "Host",
                        "addChild",
                        "org.apache.catalina.Container");
 
    digester.addCallMethod(prefix + "Host/Alias",
                           "addAlias", 0);
 
    //Cluster configuration start
    digester.addObjectCreate(prefix + "Host/Cluster",
                             null, // MUST be specified in the element
                             "className");
    digester.addSetProperties(prefix + "Host/Cluster");
    digester.addSetNext(prefix + "Host/Cluster",
                        "setCluster",
                        "org.apache.catalina.Cluster");
    //Cluster configuration end
 
    digester.addObjectCreate(prefix + "Host/Listener",
                             null, // MUST be specified in the element
                             "className");
    digester.addSetProperties(prefix + "Host/Listener");
    digester.addSetNext(prefix + "Host/Listener",
                        "addLifecycleListener",
                        "org.apache.catalina.LifecycleListener");
 
    digester.addRuleSet(new RealmRuleSet(prefix + "Host/"));
 
    digester.addObjectCreate(prefix + "Host/Valve",
                             null, // MUST be specified in the element
                             "className");
    digester.addSetProperties(prefix + "Host/Valve");
    digester.addSetNext(prefix + "Host/Valve",
                        "addValve",
                        "org.apache.catalina.Valve");
}

该方法中完成了如下几项工作:

  • 创建Host实例,通过addChild()方法添加到Engine上
  • 为Host添加了一个生命周期监听器HostConfig,这个监听器是代码里写死,不是通过server.xml配置的。这里的HostConfig在后面的文章介绍Context构建时,会重点提到
  • 为Host配置集群,所以集群的配置即可以在Engine级别,也可以在Host级别
  • 为Host添加生命周期监听器,这里的监听器是server.xml文件中配置的
    为Host添加Valve,具体的拦截器由className属性指定,不指定默认值

5.7.3 Context解析

多数情况下,我们并不需要在server.xml中配置Context,而是由HostConfig自动扫描部署目录,以context.xml文件为基础进行解析创建。
Context的解析,是在digester.addRuleSet(new ContextRuleSet(“Server/Service/Engine/Host/”));方法中完成的,最终ContextRuleSet的addRuleInstances会生效,将规则添加到Digester,如下所示:

public void addRuleInstances(Digester digester) { 
    // 1. 创建Context实例,通过server.xml配置Context时,create是true,需要创建Context实例;通过HostConfig创建Context时,create为false,此时仅需要解析节点即可
    if (create) {
        digester.addObjectCreate(prefix + "Context",
                "org.apache.catalina.core.StandardContext", "className");
        digester.addSetProperties(prefix + "Context");
    } else {
        digester.addSetProperties(prefix + "Context", new String[]{"path", "docBase"});
    }
 
    if (create) {
        digester.addRule(prefix + "Context",
                         new LifecycleListenerRule
                             ("org.apache.catalina.startup.ContextConfig",
                              "configClass"));
        digester.addSetNext(prefix + "Context",
                            "addChild",
                            "org.apache.catalina.Container");
    }
 
    // 2. 为Context添加生命周期监听器
    digester.addObjectCreate(prefix + "Context/Listener",
                             null, // MUST be specified in the element
                             "className");
    digester.addSetProperties(prefix + "Context/Listener");
    digester.addSetNext(prefix + "Context/Listener",
                        "addLifecycleListener",
                        "org.apache.catalina.LifecycleListener");
 
    // 3. 为Context指定类加载器,默认为org.apache.catalina.loader.WebappLoader
    digester.addObjectCreate(prefix + "Context/Loader",
                        "org.apache.catalina.loader.WebappLoader",
                        "className");
    digester.addSetProperties(prefix + "Context/Loader");
    digester.addSetNext(prefix + "Context/Loader",
                        "setLoader",
                        "org.apache.catalina.Loader");
 
    // 4. 为Context添加会话管理器,默认实现为StandardManager
    digester.addObjectCreate(prefix + "Context/Manager",
                             "org.apache.catalina.session.StandardManager",
                             "className");
    digester.addSetProperties(prefix + "Context/Manager");
    digester.addSetNext(prefix + "Context/Manager",
                        "setManager",
                        "org.apache.catalina.Manager");
 
    digester.addObjectCreate(prefix + "Context/Manager/Store",
                             null, // MUST be specified in the element
                             "className");
    digester.addSetProperties(prefix + "Context/Manager/Store");
    digester.addSetNext(prefix + "Context/Manager/Store",
                        "setStore",
                        "org.apache.catalina.Store");
 
    digester.addObjectCreate(prefix + "Context/Manager/SessionIdGenerator",
                             "org.apache.catalina.util.StandardSessionIdGenerator",
                             "className");
    digester.addSetProperties(prefix + "Context/Manager/SessionIdGenerator");
    digester.addSetNext(prefix + "Context/Manager/SessionIdGenerator",
                        "setSessionIdGenerator",
                        "org.apache.catalina.SessionIdGenerator");
 
    //5. 为Context添加初始化参数,通过该配置,为Context添加初始化参数
    digester.addObjectCreate(prefix + "Context/Parameter",
                             "org.apache.tomcat.util.descriptor.web.ApplicationParameter");
    digester.addSetProperties(prefix + "Context/Parameter");
    digester.addSetNext(prefix + "Context/Parameter",
                        "addApplicationParameter",
                        "org.apache.tomcat.util.descriptor.web.ApplicationParameter");
 
    // 6. 为Context添加安全配置以及web资源配置
    digester.addRuleSet(new RealmRuleSet(prefix + "Context/"));
 
    digester.addObjectCreate(prefix + "Context/Resources",
                             "org.apache.catalina.webresources.StandardRoot",
                             "className");
    digester.addSetProperties(prefix + "Context/Resources");
    digester.addSetNext(prefix + "Context/Resources",
                        "setResources",
                        "org.apache.catalina.WebResourceRoot");
 
    digester.addObjectCreate(prefix + "Context/Resources/PreResources",
                             null, // MUST be specified in the element
                             "className");
    digester.addSetProperties(prefix + "Context/Resources/PreResources");
    digester.addSetNext(prefix + "Context/Resources/PreResources",
                        "addPreResources",
                        "org.apache.catalina.WebResourceSet");
 
    digester.addObjectCreate(prefix + "Context/Resources/JarResources",
                             null, // MUST be specified in the element
                             "className");
    digester.addSetProperties(prefix + "Context/Resources/JarResources");
    digester.addSetNext(prefix + "Context/Resources/JarResources",
                        "addJarResources",
                        "org.apache.catalina.WebResourceSet");
 
    digester.addObjectCreate(prefix + "Context/Resources/PostResources",
                             null, // MUST be specified in the element
                             "className");
    digester.addSetProperties(prefix + "Context/Resources/PostResources");
    digester.addSetNext(prefix + "Context/Resources/PostResources",
                        "addPostResources",
                        "org.apache.catalina.WebResourceSet");
 
    // 7. 为Context添加资源连接,默认为ContextResourceLink,用于J2EE命名服务
    digester.addObjectCreate(prefix + "Context/ResourceLink",
            "org.apache.tomcat.util.descriptor.web.ContextResourceLink");
    digester.addSetProperties(prefix + "Context/ResourceLink");
    digester.addRule(prefix + "Context/ResourceLink",
            new SetNextNamingRule("addResourceLink",
                    "org.apache.tomcat.util.descriptor.web.ContextResourceLink"));
 
    // 8. 为Context添加Valve
    digester.addObjectCreate(prefix + "Context/Valve",
                             null, // MUST be specified in the element
                             "className");
    digester.addSetProperties(prefix + "Context/Valve");
    digester.addSetNext(prefix + "Context/Valve",
                        "addValve",
                        "org.apache.catalina.Valve");
 
    // 9. 为Context添加守护资源配置
    digester.addCallMethod(prefix + "Context/WatchedResource",
                           "addWatchedResource", 0);
 
    digester.addCallMethod(prefix + "Context/WrapperLifecycle",
                           "addWrapperLifecycle", 0);
 
    digester.addCallMethod(prefix + "Context/WrapperListener",
                           "addWrapperListener", 0);
 
    digester.addObjectCreate(prefix + "Context/JarScanner",
                             "org.apache.tomcat.util.scan.StandardJarScanner",
                             "className");
    digester.addSetProperties(prefix + "Context/JarScanner");
    digester.addSetNext(prefix + "Context/JarScanner",
                        "setJarScanner",
                        "org.apache.tomcat.JarScanner");
 
    digester.addObjectCreate(prefix + "Context/JarScanner/JarScanFilter",
                             "org.apache.tomcat.util.scan.StandardJarScanFilter",
                             "className");
    digester.addSetProperties(prefix + "Context/JarScanner/JarScanFilter");
    digester.addSetNext(prefix + "Context/JarScanner/JarScanFilter",
                        "setJarScanFilter",
                        "org.apache.tomcat.JarScanFilter");
 
    // 10. 为Context添加Cookie处理器
    digester.addObjectCreate(prefix + "Context/CookieProcessor",
                             "org.apache.tomcat.util.http.Rfc6265CookieProcessor",
                             "className");
    digester.addSetProperties(prefix + "Context/CookieProcessor");
    digester.addSetNext(prefix + "Context/CookieProcessor",
                        "setCookieProcessor",
                        "org.apache.tomcat.util.http.CookieProcessor");
}

通过如上Degister机制,我们实现了将server.xml解析的过程,输出结果就是相关的Tomcat的组件被实例化出来,并且维护好了组件的上下级关系。后续我们调用init方法和start方法,也是针对这些已经实例化后的组件展开的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_42242792

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值