Tomcat配置文件Server.xml解析
一 核心的解析逻辑
- 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基本架构
- DefaultHandler2:来自SAX,Digester继承该类,说明Digester底层用的是SAX
- Digester:Digester解析的核心类和入口类,客户端(需要解析xml的调用方)需要实例化该类,设置该类,并调用该类的方法
- Rules:保存XML的节点和规则的映射关系,默认实现类是RulesBase
- RuesBase:是Rules的默认实现类。当有一个XML节点开始解析时,会在这里面找是否有对应的节点,并根据节点查找对应的处理规则
- Rule:节点的处理方法,内置的或者自定义的规则都是继承自该接口
3.2 Digester解析XML文档的流程
- Client需要创建一个Digester对象
- Client必须根据自己的XML格式来添加所有的Rule
- Client调用Digester的parse操作来解析XML文件。
- 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);
- 准备用来解析server.xml文件需要用的digester
- 读取server.xml文件作为一个输入流
- 使用inputStream构造一个sax的inputSource,因为digester底层用的是sax去解析的
- 把当前类压入到digester的栈顶,用来作为digester解析出来的对象的一种引用,digester自带一个栈的结构
- 调用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方法,也是针对这些已经实例化后的组件展开的