文章目录

1.Digester 类的介绍

​apache​ ​​的​ ​Digester​ ​​库是专门用解析管理​ ​xml​ ​​文档,在​ ​tomcat​ ​​中也使用了这个第三方类库来解析xml文档,也就是对应的​ ​server.xm​ ​​l和​ ​web.xml​

​org.apache.commons.digester.Digeste​ ​​r类是​ ​Digester​ ​​库的主类,该类可以用来解析xml文档,对于xml文档中的每个元素,​ ​Digester​ ​​对象都会检查他事先预定义的事件。在调用​ ​Digester​ ​​对象​ ​parse()​ ​​方法之前,需要预先​ ​定义事件​ ​来完成解析。

2.Digester 类的使用

在之前的tomcat启动过程源码讲解的时候,我们讲过Catalina类实例的load()

​Catalina,load()​

Tomcat 源码分析 (Digester类的使用) (十)_.net

Tomcat 源码分析 (Digester类的使用) (十)_java_02

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
// 根据Server标签创建Server对象,实例是StandardServer,设置属性,并且调用前一个对象的setServer方法,将StandardServer对象设置进去
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");

// 遇到Listener标签,根据标签上className属性上类创建对应的对象,设置对应Listener的属性并且将该对象设置到StandardServer中
digester.addRule("Server/Listener",
new ListenerCreateRule(null, "className"));
digester.addSetProperties("Server/Listener");
digester.addSetNext("Server/Listener",
"addLifecycleListener",
"org.apache.catalina.LifecycleListener");

// 遇到Service标签创建StandardService对象,然后设置其属性,然后将StandardService实例设置到StandardServer中
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标签,跟上面一样创建对应的listener对象,然后设置到 StandardService对象中。
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
// 创建对应的Executor 然后设置到StandardService中
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"});
// 将Connecter实例添加到 StandardService中
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, // MUST be specified in the element
"className");
// 创建Connector 内部的listener
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/");

return digester;

}

创建对象

public void addObjectCreate(String pattern, String className)
public void addObjectCreate(String pattern, Class clazz)
public void addObjectCreate(String pattern, String className,String attributeName)
public void addObjectCreate(String pattern,String attributeName,Class clazz)

设置属性

public void addSetProperties(String pattern) 
public void addSetProperties(String pattern,String attributeName,String propertyName)
public void addSetProperties(String pattern,String [] attributeNames,String [] propertyNames)
public void addSetProperty(String pattern, String name, String value)

调用方法

public void addCallMethod(String pattern, String methodName)

创建对象之间的关系

public void addSetNext(String pattern, String methodName)
public void addSetNext(String pattern, String methodName,String paramType)

向Digester类中再添加规则

public void addRuleSet(RuleSet ruleSet)

3.Rule相关类

  • Rule
  • RuleBase
  • RuleSet

​Rule.java​

​Rule​ ​​类也是​ ​Digester​ ​​中比较重要的类,包含了一些常用的方法,比如​ ​begin()​ ​​,​ ​body()​ ​​,​ ​end()​ ​​等,当​ ​Digester​ ​​对象解析到标签开始的时候会调用​ ​begin()​ ​​方法,到标签内会调用​ ​body()​ ​​方法,在标签末位的时候会调用​ ​end()​ ​​方法。我们可以查看下​ ​addObjectCreate​ ​方法看看,该方法如何实现。

Tomcat 源码分析 (Digester类的使用) (十)_.net_03

public void addRule(String pattern, Rule rule) {

rule.setDigester(this);
getRules().add(pattern, rule);

}

public Rules getRules() {
if (this.rules == null) {
this.rules = new RulesBase();
this.rules.setDigester(this);
}
return this.rules;
}

​addRule​ ​​是往​ ​Digester​ ​​内部的一个对象​ ​rules​ ​​中添加了一条​ ​rule​ ​​,而其中​ ​rules​ ​​指向的是一个​ ​RuleBase​ ​对象

​RuleBase.java​

​RuleBase​ ​​代表​ ​Digester​ ​​类包含的所有规则集合, ​ ​RuleBase​ ​​内部有个​ ​HashMap​ ​存放着所有的规则,map的key是匹配规则,值是该规则对应的所有Rule的集合。

Tomcat 源码分析 (Digester类的使用) (十)_tomcat_04

@Override
public void add(String pattern, Rule rule) {
// to help users who accidentally add '/' to the end of their patterns
int patternLength = pattern.length();
if (patternLength>1 && pattern.endsWith("/")) {
pattern = pattern.substring(0, patternLength-1);
}

List<Rule> list = cache.get(pattern);
if (list == null) {
list = new ArrayList<>();
cache.put(pattern, list);
}
list.add(rule);
rules.add(rule);
if (this.digester != null) {
rule.setDigester(this.digester);
}
}

​ConnectorCreateRule.java​

继承了​ ​Rule​ ​​对象,复写了​ ​begin​ ​方法

@Override
public void begin(String namespace, String name, Attributes attributes)
throws Exception {
Service svc = (Service) digester.peek();
Executor ex = null;
String executorName = attributes.getValue("executor");
if (executorName != null ) {
ex = svc.getExecutor(executorName);
}
String protocolName = attributes.getValue("protocol");
Connector con = new Connector(protocolName);
if (ex != null) {
setExecutor(con, ex);
}
String sslImplementationName = attributes.getValue("sslImplementationName");
if (sslImplementationName != null) {
setSSLImplementationName(con, sslImplementationName);
}
digester.push(con);

StringBuilder code = digester.getGeneratedCode();
if (code != null) {
code.append(System.lineSeparator());
code.append(Connector.class.getName()).append(' ').append(digester.toVariableName(con));
code.append(" = new ").append(Connector.class.getName());
code.append("(new ").append(con.getProtocolHandlerClassName()).append("());");
code.append(System.lineSeparator());
if (ex != null) {
code.append(digester.toVariableName(con)).append(".getProtocolHandler().setExecutor(");
code.append(digester.toVariableName(svc)).append(".getExecutor(").append(executorName);
code.append("));");
code.append(System.lineSeparator());
}
if (sslImplementationName != null) {
code.append("((").append(AbstractHttp11JsseProtocol.class.getName()).append("<?>) ");
code.append(digester.toVariableName(con)).append(".getProtocolHandler()).setSslImplementationName(\"");
code.append(sslImplementationName).append("\");");
code.append(System.lineSeparator());
}
}
}

​RuleSet.java​

Tomcat 源码分析 (Digester类的使用) (十)_apache_05

实现类

Tomcat 源码分析 (Digester类的使用) (十)_.net_06


​EngineRuleSet.addRuleInstances()​

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

完善创建​ ​StandardEngine​ ​对象并且设置内部各种属性和对象的引用。

​HostRuleSet,ContextRuleSet​ ​ 差不多