Tomcat9如何加載server.xml
小編給大家分享一下Tomcat9如何加載server.xml,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
1.Tomcat啟動
org.apache.catalina.startup.Bootstrap.main(String args[])
?public?static?void?main(String?args[])?{ ????????synchronized?(daemonLock)?{ ????????????if?(daemon?==?null)?{ ????????????????Bootstrap?bootstrap?=?new?Bootstrap(); ????????????????try?{ ????????????????????bootstrap.init();?//初始化類加載器 ????????????????}?catch?(Throwable?t)?{ ????????????????????handleThrowable(t); ????????????????????t.printStackTrace(); ????????????????????return; ????????????????} ????????????????daemon?=?bootstrap; ????????????}?else?{ ????????????????Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); ????????????} ????????} ????????//根據傳入的不同指令,進行相應處理 ????????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方法中主要為兩部分邏輯:
調用bootstrap.init()進行初始化
根據傳入不同的指令進行相應的處理,本文主要分析start指定,即服務啟動。啟動服務start主要調用了org.apache.catalina.startup.Catalina.load()和start()方法
org.apache.catalina.startup.Bootstrap.init()
?public?void?init()?throws?Exception?{ ????????initClassLoaders();?//初始化類加載 ????????Thread.currentThread().setContextClassLoader(catalinaLoader);?//設置當前線程的類加載器為catalinaLoader ????????SecurityClassLoad.securityClassLoad(catalinaLoader);?//啟用java安全管理的處理 ????????//通過反射的方式實例化org.apache.catalina.startup.Catalina,并設置父類加載器為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; ????}
類加載器的初始化,創建commonLoader、catalinaLoader、sharedLoader,具體可參考上一篇 《Tomcat9源代碼淺析-類加載體系》
啟用java安全管理的處理
通過反射的方式實例化org.apache.catalina.startup.Catalina,并設置父類加載器為sharedLoader
org.apache.catalina.security.SecurityClassLoad
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); ????}
當時使用Java SecurityManager時,會提前加載一些必要的java類,以避免觸發權限異常AccessControlException
2.server.xml解析框架
2.1 SAX
Tomcat中使用SAX解析server.xml文件。SAX解析方式會逐行的解析XML文檔,當遇到標簽時會觸發解析處理器,采用事件處理的方式解析XML,它的優點是不需要將完整的XML文檔加載進內存,可以在讀取文檔的同時就進行解析,節省內存,適合解析超大XML,主要方法有:
startDocument():文檔解析開始時調用,該方法只會調用一次
startElement(String uri, String localName, String qName, Attributes attributes):標簽解析開始時調用
endElement(String uri, String localName, String qName):標簽(節點)解析結束后調用
endDocument():文檔解析結束后調用,該方法只會調用一次
2.2 規則Rules
Tomcat將server.xml的解析抽象為規則,利用Java的引用傳遞,通過有副作用的void方法,對xml進行解析,規則調用的順序與xml解析的順序是一致的,即start方法是正序,end方法是逆序。
規則中包含以下方法:
begin:Degister.startElement 方法調用
body、end:Degister.endElement方法中調用,先調用body,再調用end
finish:Degister.endDocument方法中調用
Tomcat中常見的規則類型:
ObjectCreateRule 創建對應class的對象實例,并放到Designer的堆棧成員屬性中
SetPropertiesRule 獲取堆棧中棧頂的元素,并將xml元素的屬性賦值給對象實例
SetNextRule 調用父節點的實例對象,將當前對象作為參數,反射調用某個方法
ListenerCreateRule 當Listener標簽有optional屬性為true時,創建實例異常時,強制添加OptionalListener實例
ConnectorCreateRule 創建Connector實例
SetAllPropertiesRule 主體功能與SetPropertiesRule 一致,這個Rule可以排除一些屬性的設置
AddPortOffsetRule Set portOffset on all the connectors based on portOffset in the Server
CertificateCreateRule 實例化SSLHostConfigCertificate
3.server.xml解析源代碼解析
org.apache.catalina.startup.Catalina.load()
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(); ????????//?創建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; ????????} ????????//設置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指令邏輯,通過反射調用Catalina.load()
Catalina.load() 讀取conf/server.xml,創建解析xml的Digester
開始初始化server
org.apache.catalina.startup.Catalina.createStartDigester()
?protected?Digester?createStartDigester()?{ ????????long?t1=System.currentTimeMillis(); ????????//?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,?//?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; ????}
此方法創建解析server.xml的Digester,根據server.xml的元素標簽,為每個標簽設置相應的規則組,在解析標簽時進行調用。
由此也可以得到結論,server.xml的結構就是Tomcat容器內部的結構,通過對server.xml的解析規則的執行,實例化出Tomcat容器結構。
以下為Tomcat9默認的server.xml
<?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"> ????????<!--?This?Realm?uses?the?UserDatabase?configured?in?the?global?JNDI ?????????????resources?under?the?key?"UserDatabase".??Any?edits ?????????????that?are?performed?against?this?UserDatabase?are?immediately ?????????????available?for?use?by?the?Realm.??--> ????????<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>
其結構見下圖:
Server代表服務器,一個Tomcat只有一個Server
Service 代表服務: 一個Server可以對外提供多個服務
Connector連接器: service服務的核心組成之一,主要是鏈接客戶端請求
Container容器:service服務的核心組成之一,主要是執行業務邏輯,這里按層級為Engine、Host、Context
Wrapper:對應Servlet的定義
以上是“Tomcat9如何加載server.xml”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注蝸牛博客行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:niceseo99@gmail.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。
評論