LifecycleBase生命周期抽象類
在分析啟動(dòng)流程之前氯哮,有必要對(duì)于實(shí)現(xiàn)了LifecycleBase這個(gè)類的所有類進(jìn)行分析。結(jié)論是只要調(diào)用生命周期方法食铐,都會(huì)先調(diào)用這個(gè)LifecycleBase的父類方法遭京。以StandardServer和StandardEngine容器類為例
1、StandardServer
在具體分析之前需要看下StandardServer的繼承關(guān)系圖
StandardServer繼承了生命周期抽象類LifecycleMBeanBase柳畔,LifecycleMBeanBase繼承了LifecycleBase抽象類。由于StandardServer沒(méi)有init辜昵、start荸镊、stop咽斧、destroy等方法堪置,所以會(huì)到父類尋找這些方法。
①张惹、init
org.apache.catalina.util.LifecycleBase#init
調(diào)用setStateInternal方法
發(fā)布LifecycleState.INITIALIZING是before_init的生命周期事件
②舀锨、setStateInternal
org.apache.catalina.util.LifecycleBase#setStateInternal
這個(gè)方法最重要的實(shí)現(xiàn)邏輯就是發(fā)布當(dāng)前事件
③、fireLifecycleEvent
org.apache.catalina.util.LifecycleBase#fireLifecycleEvent
根據(jù)傳入類型type = "before_init"獲取當(dāng)前事件宛逗,然后調(diào)用當(dāng)前容器包含的LifecycleListener的lifecycleEvent方法坎匿。
④、initInternal
initInternal方法會(huì)調(diào)用到當(dāng)前容器的initInternal方法。
2替蔬、StandardEngine繼承圖
繼承了ContainerBase告私,ContainerBase繼承了LifecycleMBeanBase并實(shí)現(xiàn)了Container。
LifecycleMBeanBase繼承了LifecycleBase抽象類承桥。
①驻粟、start
org.apache.catalina.util.LifecycleBase#start
發(fā)布LifecycleState.STARTING_PREP是before_start事件
②、startInternal
然后調(diào)用startInternal方法
Lifecycle有哪些LifecycleState事件
before_init凶异、after_init蜀撑、start、before_start剩彬、after_start酷麦、stop、before_stop喉恋、after_stop沃饶、after_destroy、before_destroy瀑晒、periodic绍坝、configure_start、configure_stop
所以苔悦,任何容器類StandardService轩褐、StandardEngine、StandardHost玖详、StandardContext把介、StandardWrapper及其他實(shí)現(xiàn)了LifecycleBase調(diào)用生命周期方法都是這樣的調(diào)用流程
Bootstrap啟動(dòng)Tomcat
Tomcat啟動(dòng)通過(guò)Bootstrap類main方法啟動(dòng)
org.apache.catalina.startup.Bootstrap#main
main方法主要步驟有三步:
①、init()
②蟋座、load()
③拗踢、start()
1、init
org.apache.catalina.startup.Bootstrap#init()
①向臀、初始化類加載器
org.apache.catalina.startup.Bootstrap#initClassLoaders
commonLoader巢墅、catalinaLoader、sharedLoader類加載器都是URLClassLoader
當(dāng)前線程設(shè)置類加載器catalinaLoader
②券膀、啟動(dòng)類加載并創(chuàng)建實(shí)例對(duì)象Catalina
設(shè)置Catalina類的父加載器setParentClassLoader是URLClassLoader
setAwait
catalina設(shè)置Await是阻塞君纫,true表示阻塞
2、load
org.apache.catalina.startup.Bootstrap#load
org.apache.catalina.startup.Catalina#load()
①芹彬、創(chuàng)建Digester
獲取file文件conf\server.xml蓄髓,創(chuàng)建Digester對(duì)象。這個(gè)類的目的就是把server.xml中的層級(jí)結(jié)構(gòu)和生命周期實(shí)現(xiàn)類都創(chuàng)建出來(lái)舒帮,包括容器類和監(jiān)聽(tīng)器類会喝。
org.apache.catalina.startup.Catalina#createStartDigester
digester對(duì)象是解析server.xml文件
fakeAttributes通過(guò)鍵值對(duì)添加
digester的規(guī)則添加到Rules對(duì)象
digester解析文件reader = SAXParserImpl$JAXPSAXParser
②陡叠、server.init初始化
設(shè)置server的Catalina屬性
開(kāi)始server的init
容器對(duì)象都實(shí)現(xiàn)了LifecycleBase聲明周期方法,所以容器對(duì)象都會(huì)調(diào)用到org.apache.catalina.util.LifecycleBase#init肢执,然后調(diào)用到容器的initInternal方法
org.apache.catalina.core.StandardServer#initInternal
③枉阵、services.init()
org.apache.catalina.util.LifecycleBase#init
org.apache.catalina.core.StandardService#initInternal
④、engine.init()
org.apache.catalina.core.StandardEngine#initInternal
org.apache.catalina.core.StandardEngine#getRealm
org.apache.catalina.core.ContainerBase#initInternal
org.apache.catalina.core.ContainerBase#reconfigureStartStopExecutor
創(chuàng)建內(nèi)嵌的startStopExecutor執(zhí)行器预茄,用來(lái)處理部分容器類
⑤岭妖、executor.init()和mapperListener..init()
如果有自定義executors將會(huì)進(jìn)行初始化
⑥、connector.init()
初始化連接
初始化adapter
org.apache.catalina.connector.Connector#initInternal
protocolHandler = Http11NioProtocol驗(yàn)證是否有效
org.apache.coyote.http11.AbstractHttp11Protocol#init
org.apache.coyote.AbstractProtocol#init
org.apache.tomcat.util.net.AbstractEndpoint#init
org.apache.tomcat.util.net.AbstractEndpoint#bindWithCleanup
org.apache.tomcat.util.net.NioEndpoint#bind
org.apache.tomcat.util.net.NioEndpoint#initServerSocket
創(chuàng)建serverSock對(duì)象反璃,綁定端口昵慌,設(shè)置為非阻塞。服務(wù)端sockets啟動(dòng)
到這里便開(kāi)啟服務(wù)端Socket等待客戶端連接
3淮蜈、start
org.apache.catalina.startup.Bootstrap#start
3.1斋攀、StandardServer啟動(dòng)start
org.apache.catalina.startup.Catalina#start
這里也會(huì)調(diào)用到父類LifecycleBase#start方法
org.apache.catalina.util.LifecycleBase#start
org.apache.catalina.core.StandardServer#startInternal
3.2、StandardService啟動(dòng)start
開(kāi)啟services
開(kāi)啟一個(gè)startPeriodicLifecycleEvent梧田,用來(lái)后臺(tái)執(zhí)行進(jìn)行熱加載和熱部署
此時(shí)處于StandardService階段淳蔼,這里的lifecycleListeners 數(shù)量是0,所以setState方法什么都沒(méi)做
3.3裁眯、StandardEngine啟動(dòng)start
開(kāi)啟engine
開(kāi)啟engine后
主要步驟是:executor鹉梨、mapperListener、connector的開(kāi)啟
org.apache.catalina.core.StandardEngine#startInternal
在StandardEngine階段穿稳,lifecycleListeners有EngineConfig監(jiān)聽(tīng)器
org.apache.catalina.core.ContainerBase#startInternal
步驟包括:cluster存皂、realm的start調(diào)用、獲取孩子容器StandardHost
主要分析獲取的孩子容器StandardHost
把得到的孩子容器封裝成StartChild任務(wù)類逢艘,使用startStopExecutor線程池開(kāi)啟任務(wù)
3.3.1旦袋、executor啟動(dòng)start
executors線程池為null這里沒(méi)有做什么
3.3.2、mapperListener啟動(dòng)start
org.apache.catalina.mapper.MapperListener#startInternal
org.apache.catalina.mapper.MapperListener#addListeners
listeners和lifecycleListeners添加MapperListener監(jiān)聽(tīng)器它改,然后遞歸調(diào)用為孩子容器都添加這個(gè)MapperListener監(jiān)聽(tīng)器
org.apache.catalina.mapper.MapperListener#registerHost
org.apache.catalina.mapper.MapperListener#registerContext
org.apache.catalina.mapper.MapperListener#prepareWrapperMappingInfo
對(duì)每個(gè)wrapper尋找對(duì)應(yīng)的映射關(guān)系并添加到wrappers中
3.3.3疤孕、connector啟動(dòng)start
org.apache.catalina.core.StandardService#startInternal
org.apache.catalina.connector.Connector#startInternal
org.apache.coyote.AbstractProtocol#start
org.apache.tomcat.util.net.AbstractEndpoint#start
org.apache.tomcat.util.net.NioEndpoint#startInternal
創(chuàng)建executor工作線程池
poller線程啟動(dòng)
acceptor線程啟動(dòng)
3.4、StandardHost啟動(dòng)start
org.apache.catalina.core.ContainerBase.StartChild#call
lifecycleListeners包含HostConfig央拖,所以在執(zhí)行start之前
org.apache.catalina.util.LifecycleBase#start
org.apache.catalina.util.LifecycleBase#setStateInternal
發(fā)布一個(gè)lifecycleEvent = "before_start"事件
org.apache.catalina.util.LifecycleBase#fireLifecycleEvent
HostConfig監(jiān)聽(tīng)器處理before_start事件
org.apache.catalina.startup.HostConfig#lifecycleEvent
check()方法是periodic事件祭阀,用來(lái)熱部署。beforeStart就是before_start事件
org.apache.catalina.startup.HostConfig#beforeStart
得到webapps和conf/Catalina/loaclhost文件夾
org.apache.catalina.core.StandardHost#startInternal
pipeline添加閾值通過(guò)addValve
調(diào)用父類方法
StandardHost[localhost]尋找孩子容器鲜戒,與StandardEngine過(guò)程相同
封裝成StartChild交給startStopExecutor線程池處理
3.5专控、StandardContext啟動(dòng)start
此時(shí)lifecycleListeners包括(CopyOnWriteArrayList 3個(gè)):ContextConfig、StandardHost$MemoryLeakTrackingListener 袍啡、ThreadLocalLeakPreventionListener
org.apache.catalina.util.LifecycleBase#setStateInternal
發(fā)布LifecycleState.STARTING_PREP事件是before_start
org.apache.catalina.util.LifecycleBase#fireLifecycleEvent
對(duì)三個(gè)監(jiān)聽(tīng)器LifecycleListener調(diào)用lifecycleEvent
org.apache.catalina.startup.ContextConfig#lifecycleEvent
org.apache.catalina.startup.ContextConfig#fixDocBase
調(diào)整docBase
org.apache.catalina.startup.ContextConfig#antiLocking
對(duì)antiResourceLocking是true的處理踩官,默認(rèn)是false
另外兩個(gè)LifecycleListener什么都沒(méi)做
StandardContext.startInternal()
org.apache.catalina.core.StandardContext#startInternal
①却桶、設(shè)置resources
org.apache.catalina.core.StandardContext#setResources
把傳入的resources賦值給this(StandardContext)的resources
②境输、resources的啟動(dòng)
org.apache.catalina.core.StandardContext#resourcesStart
StandardRoot實(shí)現(xiàn)了LifecycleBase蔗牡,所以直接到startInternal方法
org.apache.catalina.webresources.StandardRoot#startInternal
org.apache.catalina.webresources.StandardRoot#createMainResourceSet
創(chuàng)建包含當(dāng)前Context的路徑的WebResourceSet并返回
org.apache.catalina.webresources.StandardRoot#processWebInfLib
jar包資源resources也添加到StandradRoot的allResources中
③、創(chuàng)建webappLoader類嗅剖,并設(shè)置到當(dāng)前Context的loader中
④辩越、當(dāng)前應(yīng)用加載器loader,啟動(dòng)start
WebappLoader實(shí)現(xiàn)了LifecycleBase
org.apache.catalina.loader.WebappLoader#startInternal
org.apache.catalina.loader.WebappLoader#createClassLoader
根據(jù)ParallelWebappClassLoader類的構(gòu)造方法信粮,傳入父類加載器參是URLClassLoader黔攒。創(chuàng)建一個(gè)WebappClassLoaderBase對(duì)象。傳入的resources是StandardRoot對(duì)象
org.apache.catalina.loader.WebappClassLoaderBase#start
把resources中的/WEB-INF/classes和/WEB-INF/lib目錄添加到localRepositories中
⑤强缘、解析web.xml文件
org.apache.catalina.startup.ContextConfig#lifecycleEvent
org.apache.catalina.startup.ContextConfig#webConfig
org.apache.tomcat.util.descriptor.web.WebXmlParser#parseWebXml(org.xml.sax.InputSource, org.apache.tomcat.util.descriptor.web.WebXml, boolean)
org.apache.tomcat.util.digester.Digester#parse(org.xml.sax.InputSource)
reader = SAXParserImpl$JAXPSAXParser
解析到servlets督惰、servletMappings、 filters旅掂、 filterMaps等屬性中
⑥赏胚、尋找ServletContainerInitializer實(shí)現(xiàn)
org.apache.catalina.startup.ContextConfig#processServletContainerInitializers
加載后的實(shí)現(xiàn)放入到detectedScis集合中
得到HandlesTypes注解
⑦、processClasses商虐、合并web-fragment.xml觉阅、合并tomcat-web.xml
⑧、JSP處理秘车、把web.xml配置到Context
org.apache.catalina.startup.ContextConfig#configureContext
配置filter典勇、filterMap、listener
SecurityConstraint叮趴、role割笙、ContextService
servlet設(shè)置
ServletMapping、sessionConfig
配置PostConstruct眯亦、PreDestroy方法
ServletContainerInitializer實(shí)現(xiàn)添加到context中
⑨咳蔚、回調(diào)ServletContainerInitializers的onStartup方法
3.6、部署應(yīng)用
發(fā)布LifecycleState.STARTING是start的事件
org.apache.catalina.core.ContainerBase#startInternal
這里是StandardHost容器階段搔驼。時(shí)機(jī)是在開(kāi)始Host谈火,把Host的孩子容器節(jié)點(diǎn)封裝到StartChild任務(wù)類,在線程池startStopExecutor調(diào)用的舌涨,然后調(diào)用results的get回調(diào)方法糯耍,pipeline開(kāi)始方法之后調(diào)用的
org.apache.catalina.startup.HostConfig#lifecycleEvent
設(shè)置copyXML(false)、deployXML(true)囊嘉、unpackWARs(true)温技、contextClass(org.apache.catalina.core.StandardContext)的參數(shù)值
org.apache.catalina.startup.HostConfig#start
deployApps()部署應(yīng)用
org.apache.catalina.startup.HostConfig#deployApps()
①、deployDescriptors
org.apache.catalina.startup.HostConfig#deployDescriptors
處理部署在conf/Catalina/localhost/文件夾下XML形式的context
如果沒(méi)有部署過(guò)則封裝成DeployDescriptor任務(wù)類放到InlineExecutorService執(zhí)行
②扭粱、deployWARs
org.apache.catalina.startup.HostConfig#deployWARs
部署war文件舵鳞,webapps目錄下以.war結(jié)尾的
如果沒(méi)有部署過(guò)則封裝成DeployWar任務(wù)類放到InlineExecutorService執(zhí)行
③、deployDirectories
處理webapps目錄下的文件夾
org.apache.catalina.startup.HostConfig#deployDirectories
如果沒(méi)有部署過(guò)則封裝成DeployDirectory任務(wù)類放到InlineExecutorService執(zhí)行
總結(jié):
Tomcat的啟動(dòng)時(shí)通過(guò)啟動(dòng)類的main方法琢蛤,主要有三步:初始化(init)蜓堕、加載(load)抛虏、啟動(dòng)(start)
1、初始化類加載器和Catalina類
2套才、根據(jù)server.xml創(chuàng)建Digester迂猴,所定義的節(jié)點(diǎn)都會(huì)生成對(duì)應(yīng)的對(duì)象,節(jié)點(diǎn)所處的層級(jí)也會(huì)解析出來(lái)背伴,設(shè)置不同容器的pipeline基礎(chǔ)的Value閾值沸毁。server、services傻寂、engine息尺、executor、mapperListener疾掰、connector的初始化調(diào)用掷倔,其中最重要的是endpoint的serverSocket的創(chuàng)建
3、StandardServer个绍、StandardService和StandardEngine勒葱、StandardHost、StandardContext等容器的啟動(dòng)巴柿。
①凛虽、由于都實(shí)現(xiàn)了生命周期抽象類,所以會(huì)先調(diào)用LifecycleBase方法广恢。在LifecycleBase方法內(nèi)會(huì)使用調(diào)用setStateInternal發(fā)布一個(gè)事件凯旋,根據(jù)當(dāng)前所處的容器階段會(huì)調(diào)用相對(duì)應(yīng)的監(jiān)聽(tīng)器實(shí)現(xiàn)類。之后再調(diào)用所處容器的生命周期方法钉迷。
②至非、StandardHost和StandardContext都是在父類容器查找孩子容器然后封裝成一個(gè)任務(wù)類放入到線程池中執(zhí)行啟動(dòng)的。
③糠聪、在容器啟動(dòng)中荒椭,其中StandardContext的啟動(dòng)是最核心一個(gè)也是復(fù)雜的一個(gè)。主要包括WebappLoader類加載器創(chuàng)建和啟動(dòng)舰蟆、解析web.xml文件(把解析后的值放到WebXML對(duì)象)趣惠、ServletContainerInitializers的查找及啟動(dòng)、把WebXML對(duì)象封裝到當(dāng)前Context對(duì)象等過(guò)程
④身害、容器啟動(dòng)后味悄,就要部署應(yīng)用。有三種部署形式塌鸯,也都是封裝成任務(wù)類放入到線程池內(nèi)執(zhí)行侍瑟。部署應(yīng)用分為部署server.xml中定義的Context和部署webapp文件夾下的Context