引言 在执行catalina的load方法时,会执行配置Digester、读取配置文件、将Catalina作为digester的顶级容器、digester解析配置文件并注入各个组件。 简略修改了一下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Digester digester = createStartDigester(); File file = configFile();InputSource inputStream = new FileInputStream (file);InputSource inputSource = new InputSource (file.toURI().toURL().toString());inputSource.setByteStream(inputStream); digester.push(this ); digester.parse(inputSource);
Digeter是apache的common项目,作用是将XML转化成对象,使用者直接从对象中获取xml的节点信息。 Digester是对SAX的包装,它也是基于文件流来解析xml文件,只不过这些解析操作对用户是透明的。 在分析createStartDigester之前很有必要贴一下server.xml配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 protected Digester createStartDigester () { long t1 = System.currentTimeMillis(); 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 ); 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.addObjectCreate("Server/Listener" , 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" ); 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.addRule("Server/Service/Connector" , new SetAllPropertiesRule ( new String []{"executor" , "sslImplementationName" , "protocol" })); digester.addSetNext("Server/Service/Connector" , "addConnector" , "org.apache.catalina.connector.Connector" ); 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" ); 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" ); 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/" )); 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 1 2 3 4 5 6 7 8 9 10 digester.addObjectCreate("Server" , "org.apache.catalina.core.StandardServer" , "className" ); digester.addSetProperties("Server" ); digester.addSetNext("Server" , "setServer" , "org.apache.catalina.Server" );
创建StandardServer实例对象,这是属性,调用上一个元素Catalina的setServer方法。 现在栈顶元素为StandardServer实例对象,也就是Server的外层元素是Catalina。
1 2 3 public void setServer (Server server) { this .server = server; }
Service 1 2 3 4 5 6 7 8 9 //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方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Override public void addService (Service service) { service.setServer(this ); synchronized (servicesLock) { Service results[] = new Service [services.length + 1 ]; System.arraycopy(services, 0 , results, 0 , services.length); results[services.length] = service; services = results; if (getState().isAvailable()) { try { service.start(); } catch (LifecycleException e) { } } support.firePropertyChange("service" , null , service); } }
可以看出Server与Service是一对多的关系。
Connector 1 2 3 4 5 6 7 8 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方法建立联系。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public void addConnector (Connector connector) { 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); } } support.firePropertyChange("connector" , null , connector); } }
从这可以看出Service组件与Connector组件是一对多的关系。
Engine 1 digester.addRuleSet(new EngineRuleSet ("Server/Service/" ));
EngineRuleSet实现了RuleSet接口,当解析xml时会调用addRuleInstances方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 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" ); digester.addObjectCreate(prefix + "Engine/Cluster" , null , "className" ); digester.addSetProperties(prefix + "Engine/Cluster" ); digester.addSetNext(prefix + "Engine/Cluster" , "setCluster" , "org.apache.catalina.Cluster" ); digester.addObjectCreate(prefix + "Engine/Listener" , null , "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 , "className" ); digester.addSetProperties(prefix + "Engine/Valve" ); digester.addSetNext(prefix + "Engine/Valve" , "addValve" , "org.apache.catalina.Valve" ); }
套路还是一样的,先解析一层,之后再返回上一层。最终会执行到StandardService的setContainer方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public void setContainer (Engine engine) { Engine oldEngine = this .engine; if (oldEngine != null ) { oldEngine.setService(null ); } 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); } } 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); } } } support.firePropertyChange("container" , oldEngine, this .engine); }
可以看出Service与Engine引擎是一对一的关系。
Host 1 digester.addRuleSet(new HostRuleSet ("Server/Service/Engine/" ));
能看出来Host在Engine的下一层。最终会执行StandardEngine的addChild方法,将Host容器置于Engine内部。
Context 1 digester.addRuleSet(new ContextRuleSet ("Server/Service/Engine/Host/" ));
Context在Host的下一层,也会执行StandardHost的addChild方法,将Context容器置于Host容器内部。
发现没,这里没涉及到Wrapper容器,它是什么时候产生的呢? 这里先保留,等后面遇到再说。
至此,server.xml配置文件的解析差不多就了解了,也知道了Catalina中的Server组件是怎么注入的,还了解了Server、Service、Engine、Host、Context之间的关系。