文章首发于: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配置:
这个是默认配置,我将注释之类去除了。
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, List> fakeAttributes = new HashMap<>();
List 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之间的关系。