小編給大家分享一下Tomcat9如何加載server.xml,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
站在用戶(hù)的角度思考問(wèn)題,與客戶(hù)深入溝通,找到石首網(wǎng)站設(shè)計(jì)與石首網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶(hù)體驗(yàn)好的作品,建站類(lèi)型包括:網(wǎng)站制作、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、國(guó)際域名空間、雅安服務(wù)器托管、企業(yè)郵箱。業(yè)務(wù)覆蓋石首地區(qū)。public static void main(String args[]) { synchronized (daemonLock) { if (daemon == null) { Bootstrap bootstrap = new Bootstrap(); try { bootstrap.init(); //初始化類(lèi)加載器 } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon = bootstrap; } else { Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } } //根據(jù)傳入的不同指令,進(jìn)行相應(yīng)處理 try { String command = "start"; if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[args.length - 1] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); daemon.load(args); daemon.start(); if (null == daemon.getServer()) { System.exit(1); } } else if (command.equals("stop")) { daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null == daemon.getServer()) { System.exit(1); } System.exit(0); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { if (t instanceof InvocationTargetException && t.getCause() != null) { t = t.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } }
在main方法中主要為兩部分邏輯:
調(diào)用bootstrap.init()進(jìn)行初始化
根據(jù)傳入不同的指令進(jìn)行相應(yīng)的處理,本文主要分析start指定,即服務(wù)啟動(dòng)。啟動(dòng)服務(wù)start主要調(diào)用了org.apache.catalina.startup.Catalina.load()和start()方法
public void init() throws Exception { initClassLoaders(); //初始化類(lèi)加載 Thread.currentThread().setContextClassLoader(catalinaLoader); //設(shè)置當(dāng)前線程的類(lèi)加載器為catalinaLoader SecurityClassLoad.securityClassLoad(catalinaLoader); //啟用java安全管理的處理 //通過(guò)反射的方式實(shí)例化org.apache.catalina.startup.Catalina,并設(shè)置父類(lèi)加載器為sharedLoader if (log.isDebugEnabled()) log.debug("Loading startup class"); Class> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.getConstructor().newInstance(); if (log.isDebugEnabled()) log.debug("Setting startup class properties"); String methodName = "setParentClassLoader"; Class> paramTypes[] = new Class[1]; paramTypes[0] = Class.forName("java.lang.ClassLoader"); Object paramValues[] = new Object[1]; paramValues[0] = sharedLoader; Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); catalinaDaemon = startupInstance; }
類(lèi)加載器的初始化,創(chuàng)建commonLoader、catalinaLoader、sharedLoader,具體可參考上一篇 《Tomcat9源代碼淺析-類(lèi)加載體系》
啟用java安全管理的處理
通過(guò)反射的方式實(shí)例化org.apache.catalina.startup.Catalina,并設(shè)置父類(lèi)加載器為sharedLoader
public final class SecurityClassLoad { public static void securityClassLoad(ClassLoader loader) throws Exception { securityClassLoad(loader, true); } static void securityClassLoad(ClassLoader loader, boolean requireSecurityManager) throws Exception { if (requireSecurityManager && System.getSecurityManager() == null) { return; } loadCorePackage(loader); loadCoyotePackage(loader); loadLoaderPackage(loader); loadRealmPackage(loader); loadServletsPackage(loader); loadSessionPackage(loader); loadUtilPackage(loader); loadJavaxPackage(loader); loadConnectorPackage(loader); loadTomcatPackage(loader); }
當(dāng)時(shí)使用Java SecurityManager時(shí),會(huì)提前加載一些必要的java類(lèi),以避免觸發(fā)權(quán)限異常AccessControlException
Tomcat中使用SAX解析server.xml文件。SAX解析方式會(huì)逐行的解析XML文檔,當(dāng)遇到標(biāo)簽時(shí)會(huì)觸發(fā)解析處理器,采用事件處理的方式解析XML,它的優(yōu)點(diǎn)是不需要將完整的XML文檔加載進(jìn)內(nèi)存,可以在讀取文檔的同時(shí)就進(jìn)行解析,節(jié)省內(nèi)存,適合解析超大XML,主要方法有:
startDocument():文檔解析開(kāi)始時(shí)調(diào)用,該方法只會(huì)調(diào)用一次
startElement(String uri, String localName, String qName, Attributes attributes):標(biāo)簽解析開(kāi)始時(shí)調(diào)用
endElement(String uri, String localName, String qName):標(biāo)簽(節(jié)點(diǎn))解析結(jié)束后調(diào)用
endDocument():文檔解析結(jié)束后調(diào)用,該方法只會(huì)調(diào)用一次
Tomcat將server.xml的解析抽象為規(guī)則,利用Java的引用傳遞,通過(guò)有副作用的void方法,對(duì)xml進(jìn)行解析,規(guī)則調(diào)用的順序與xml解析的順序是一致的,即start方法是正序,end方法是逆序。
規(guī)則中包含以下方法:
begin:Degister.startElement 方法調(diào)用
body、end:Degister.endElement方法中調(diào)用,先調(diào)用body,再調(diào)用end
finish:Degister.endDocument方法中調(diào)用
Tomcat中常見(jiàn)的規(guī)則類(lèi)型:
ObjectCreateRule 創(chuàng)建對(duì)應(yīng)class的對(duì)象實(shí)例,并放到Designer的堆棧成員屬性中
SetPropertiesRule 獲取堆棧中棧頂?shù)脑兀ml元素的屬性賦值給對(duì)象實(shí)例
SetNextRule 調(diào)用父節(jié)點(diǎn)的實(shí)例對(duì)象,將當(dāng)前對(duì)象作為參數(shù),反射調(diào)用某個(gè)方法
ListenerCreateRule 當(dāng)Listener標(biāo)簽有optional屬性為true時(shí),創(chuàng)建實(shí)例異常時(shí),強(qiáng)制添加OptionalListener實(shí)例
ConnectorCreateRule 創(chuàng)建Connector實(shí)例
SetAllPropertiesRule 主體功能與SetPropertiesRule 一致,這個(gè)Rule可以排除一些屬性的設(shè)置
AddPortOffsetRule Set portOffset on all the connectors based on portOffset in the Server
CertificateCreateRule 實(shí)例化SSLHostConfigCertificate
public void load() { if (loaded) { return; } loaded = true; long t1 = System.nanoTime(); initDirs(); // Before digester - it may be needed initNaming(); // 讀取conf/server.xml ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile())); File file = configFile(); // 創(chuàng)建xml解析Digester Digester digester = createStartDigester(); try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) { InputStream inputStream = resource.getInputStream(); InputSource inputSource = new InputSource(resource.getURI().toURL().toString()); inputSource.setByteStream(inputStream); digester.push(this); digester.parse(inputSource); //解析xml } catch (Exception e) { log.warn(sm.getString("catalina.configFail", file.getAbsolutePath()), e); if (file.exists() && !file.canRead()) { log.warn(sm.getString("catalina.incorrectPermissions")); } return; } //設(shè)置server的屬性 getServer().setCatalina(this); getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile()); getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile()); // Stream redirection initStreams(); // 初始化server try { getServer().init(); } catch (LifecycleException e) { if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) { throw new java.lang.Error(e); } else { log.error(sm.getString("catalina.initError"), e); } } long t2 = System.nanoTime(); if(log.isInfoEnabled()) { log.info(sm.getString("catalina.init", Long.valueOf((t2 - t1) / 1000000))); } }
Bootstrap中start指令邏輯,通過(guò)反射調(diào)用Catalina.load()
Catalina.load() 讀取conf/server.xml,創(chuàng)建解析xml的Digester
開(kāi)始初始化server
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<>(); // Ignore className on all elements List objectAttrs = new ArrayList<>(); objectAttrs.add("className"); fakeAttributes.put(Object.class, objectAttrs); // Ignore attribute added by Eclipse for its internal tracking List contextAttrs = new ArrayList<>(); contextAttrs.add("source"); fakeAttributes.put(StandardContext.class, contextAttrs); // Ignore Connector attribute used internally but set on Server List 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, // MUST be specified in the element "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.addRule("Server/Service/Connector", new SetAllPropertiesRule( 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.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, // MUST be specified in the element "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, // 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; }
此方法創(chuàng)建解析server.xml的Digester,根據(jù)server.xml的元素標(biāo)簽,為每個(gè)標(biāo)簽設(shè)置相應(yīng)的規(guī)則組,在解析標(biāo)簽時(shí)進(jìn)行調(diào)用。
由此也可以得到結(jié)論,server.xml的結(jié)構(gòu)就是Tomcat容器內(nèi)部的結(jié)構(gòu),通過(guò)對(duì)server.xml的解析規(guī)則的執(zhí)行,實(shí)例化出Tomcat容器結(jié)構(gòu)。
以下為T(mén)omcat9默認(rèn)的server.xml
其結(jié)構(gòu)見(jiàn)下圖:
Server代表服務(wù)器,一個(gè)Tomcat只有一個(gè)Server
Service 代表服務(wù): 一個(gè)Server可以對(duì)外提供多個(gè)服務(wù)
Connector連接器: service服務(wù)的核心組成之一,主要是鏈接客戶(hù)端請(qǐng)求
Container容器:service服務(wù)的核心組成之一,主要是執(zhí)行業(yè)務(wù)邏輯,這里按層級(jí)為Engine、Host、Context
Wrapper:對(duì)應(yīng)Servlet的定義
以上是“Tomcat9如何加載server.xml”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道!