根據(jù)tomcat中server.xml文件解析出來的各個對象比如:Server哀军、Service沉眶、Connector等。這些容器都具有新建杉适、初始化完成沦寂、啟動、停止淘衙、失敗传藏、銷毀等狀態(tài)。tomcat的實現(xiàn)提供了對這些容器的生命周期管理彤守,深入剖析這一過程
生命周期類接口設(shè)計類圖如下:
涉及到的類的簡單介紹:
Lifecycle:定義了容器生命周期毯侦、容器狀態(tài)轉(zhuǎn)換及容器狀態(tài)遷移事件的監(jiān)聽器注冊和移除等主要接口;
LifecycleBase:作為Lifecycle接口的抽象實現(xiàn)類具垫,運用抽象模板模式將所有容器的生命周期及狀態(tài)轉(zhuǎn)換銜接起來侈离,此外還提供了生成LifecycleEvent事件的接口;
LifecycleSupport:提供有關(guān)LifecycleEvent事件的監(jiān)聽器注冊筝蚕、移除卦碾,并且使用經(jīng)典的監(jiān)聽器模式,實現(xiàn)事件生成后觸打監(jiān)聽器的實現(xiàn)起宽;
MBeanRegistration:JmxEnabled 的父類洲胖, jmx框架提供的注冊MBean的接口,引入此接口是為了便于使用JMX提供的管理功能坯沪;
LifecycleMBeanBase:Tomcat提供的對MBeanRegistration的抽象實現(xiàn)類绿映,運用抽象模板模式將所有容器統(tǒng)一注冊到JMX;
ContainerBase、StandardServer叉弦、StandardService丐一、WebappLoader、Connector淹冰、StandardContext库车、StandardEngine、StandardHost樱拴、StandardWrapper等容器都繼承了LifecycleMBeanBase柠衍,因此這些容器都具有了同樣的生命周期并可以通過JMX進行管理。
Tomcat 容器的組成:
StandardServer疹鳄、StandardService拧略、Connector芦岂、StandardContext這些容器瘪弓,彼此之間都有父子關(guān)系,每個容器都可能包含零個或者多個子容器如下:
Tomcat 容器狀態(tài):
NEW:容器剛剛創(chuàng)建時禽最,即在LifecycleBase實例構(gòu)造完成時的狀態(tài)腺怯。
INITIALIZED:容器初始化完成時的狀態(tài)。
STARTING_PREP:容器啟動前的狀態(tài)川无。
STARTING:容器啟動過程中的狀態(tài)呛占。
STARTED:容器啟動完成的狀態(tài)。
STOPPING_PREP:容器停止前的狀態(tài)懦趋。
STOPPING:容器停止過程中的狀態(tài)晾虑。
STOPPED:容器停止完成的狀態(tài)。
DESTROYED:容器銷毀后的狀態(tài)仅叫。
FAILED:容器啟動帜篇、停止過程中出現(xiàn)異常的狀態(tài)。
MUST_STOP:此狀態(tài)未使用诫咱。
MUST_DESTROY:此狀態(tài)未使用笙隙。
這些狀態(tài)都定義在枚舉類LifecycleState中。
事件與監(jiān)聽
每個容器由于繼承自LifecycleBase坎缭,當(dāng)容器狀態(tài)發(fā)生變化時竟痰,都會調(diào)用fireLifecycleEvent方法,生成LifecycleEvent掏呼,并且交由此容器的事件監(jiān)聽器處理坏快。LifecycleBase的fireLifecycleEvent方法的實現(xiàn)見代碼一:
LifecycleSupport的實現(xiàn)如下見代碼二:
將事件通知給所有監(jiān)聽當(dāng)前容器的生命周期監(jiān)聽器LifecycleListener,并調(diào)用LifecycleListener的lifecycleEvent方法憎夷。每個容器都維護這一個監(jiān)聽器緩存假消,其實現(xiàn)如下見代碼三:
每個容器在新建、初始化岭接、啟動富拗,銷毀臼予,被添加到父容器的過程中都會調(diào)用父類LifecycleBase的addLifecycleListener方法,addLifecycleListener的實現(xiàn)見代碼如見代碼四:
LifecycleBase的addLifecycleListener方法實際是對LifecycleSupport的addLifecycleListener方法的簡單代理啃沪,LifecycleSupport的addLifecycleListener方法的實現(xiàn)粘拾,見代碼五:
在代碼清單2中,我們講過容器會最終調(diào)用每個對此容器感興趣的LifecycleListener的lifecycleEvent方法创千,那么LifecycleListener的lifecycleEvent方法會做些什么呢缰雇?為了簡單起見,我們以監(jiān)聽器AprLifecycleListener為例追驴,AprLifecycleListener的lifecycleEvent方法的實現(xiàn)械哟,見代碼六:
容器生命周期
每個容器都會有自身的生命周期,其中也涉及狀態(tài)的遷移殿雪,以及伴隨的事件生成暇咆,本節(jié)詳細介紹Tomcat中的容器生命周期實現(xiàn)。所有容器的轉(zhuǎn)態(tài)轉(zhuǎn)換(如新疆丙曙、初始化爸业、啟動、停止等)都是由外到內(nèi)亏镰,由上到下進行扯旷,即先執(zhí)行父容器的狀態(tài)轉(zhuǎn)換及相關(guān)操作,然后再執(zhí)行子容器的轉(zhuǎn)態(tài)轉(zhuǎn)換索抓,這個過程是層層迭代執(zhí)行的钧忽。
容器新建
所有容器在構(gòu)造的過程中,都會首先對父類LifecycleBase進行構(gòu)造逼肯。LifecycleBase中定義了所有容器的起始狀態(tài)為LifecycleState.NEW耸黑;
所說的具體容器,實際就是LifecycleBase的具體實現(xiàn)類汉矿,目前LifecycleBase的類繼承體系崎坊;
我們對Tomcat的源碼進行分析,其處理步驟如下:
調(diào)用方調(diào)用容器父類LifecycleBase的init方法洲拇,LifecycleBase的init方法主要完成一些所有容器公共抽象出來的動作奈揍;
LifecycleBase的init方法調(diào)用具體容器的initInternal方法實現(xiàn),此initInternal方法用于對容器本身真正的初始化赋续;
具體容器的initInternal方法調(diào)用父類LifecycleMBeanBase的initInternal方法實現(xiàn)男翰,此initInternal方法用于將容器托管到JMX,便于運維管理纽乱;
LifecycleMBeanBase的initInternal方法調(diào)用自身的register方法蛾绎,將容器作為MBean注冊到MBeanServer;
容器如果有子容器,會調(diào)用子容器的init方法租冠;
容器初始化完畢鹏倘,LifecycleBase會將容器的狀態(tài)更改為初始化完畢,即LifecycleState.INITIALIZED顽爹。
對容器初始化LifecycleBase的源碼進行分析纤泵,init方法的實現(xiàn):
只有當(dāng)前容器的狀態(tài)處于LifecycleState.NEW的才可以被初始化,真正執(zhí)行初始化的方法是initInternal镜粤,當(dāng)初始化完畢捏题,當(dāng)前容器的狀態(tài)會被更改為LifecycleState.INITIALIZED。為了簡便起見肉渴,我們還是以StandardServer這個容器為例公荧,StandardServer的initInternal方法的實現(xiàn);
步驟一 ?將當(dāng)前容器注冊到JMX
StandServer調(diào)用直接父類LifecycleMBeanBase的initInternal方法,為當(dāng)前容器創(chuàng)建DynamicMBean同规,并注冊到JMX中循狰。
LifecycleMBeanBase的register方法會為當(dāng)前容器創(chuàng)建對應(yīng)的注冊名稱,以StandardServer為例捻浦,getDomain默認返回Catalina晤揣,因此StandardServer的JMX注冊名稱默認為Catalina:type=Server桥爽,真正的注冊在registerComponent方法中實現(xiàn)朱灿;
Registry的registerComponent方法會為當(dāng)前容器(如StandardServer)創(chuàng)建DynamicMBean,并且注冊到MBeanServer钠四;
步驟二將StringCache盗扒、MBeanFactory、globalNamingResources注冊到JMX缀去;其中StringCache的注冊名為Catalina:type=StringCache侣灶,MBeanFactory的注冊名為Catalina:type=MBeanFactory,globalNamingResources的注冊名為Catalina:type=NamingResources缕碎。
步驟三初始化子容器
從代碼中看到StandardServer主要對Service子容器進行初始化褥影,默認是StandardService。
注意:個別容器并不完全遵循以上的初始化過程咏雌,比如ProtocolHandler作為Connector的子容器凡怎,其初始化過程并不是由Connector的initInternal方法調(diào)用的,而是與啟動過程一道被Connector的startInternal方法所調(diào)用赊抖。
容器啟動
每個容器的start方法是自身啟動的入口统倒,其啟動過程對Tomcat的源碼進行分析,其處理步驟如下:
調(diào)用方調(diào)用容器父類LifecycleBase的start方法氛雪,LifecycleBase的start方法主要完成一些所有容器公共抽象出來的動作房匆;
LifecycleBase的start方法先將容器狀態(tài)改為LifecycleState.STARTING_PREP,然后調(diào)用具體容器的startInternal方法實現(xiàn),此startInternal方法用于對容器本身真正的初始化浴鸿;
具體容器的startInternal方法會將容器狀態(tài)改為LifecycleState.STARTING井氢,容器如果有子容器,會調(diào)用子容器的start方法啟動子容器岳链;
容器啟動完畢毙沾,LifecycleBase會將容器的狀態(tài)更改為啟動完畢,即LifecycleState.STARTED宠页。
除了初始化左胞、啟動外,各個容器還有停止和銷毀的生命周期举户,其原理與初始化烤宙、啟動類似有興趣的讀者可以自行研究