tomcat(6)生命周期
生活随笔
收集整理的這篇文章主要介紹了
tomcat(6)生命周期
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
【0】README
0.1)本文部分文字描述轉(zhuǎn)自“深入剖析tomcat”,旨在學習 “tomcat生命周期” 的基礎(chǔ)知識;
0.2)for source code, please visit ?https://github.com/pacosonTang/HowTomcatWorks/tree/master/chapter6?
0.3)溫馨建議:建議閱讀本文之前,已閱讀過 tomcat(1~5)的系列文章,因為它們是環(huán)環(huán)相扣的;
1)生命周期LifeCycle接口引入的背景:Catalina包含很多組件,當Catalina啟動或關(guān)閉時,這些組件也會啟動或關(guān)閉。而通過實現(xiàn) org.apache.catalina.Lifecyle接口,可以達到統(tǒng)一啟動或關(guān)閉這些組件的目的; 2)實現(xiàn)了Lifecycle接口的組件可以觸發(fā)一個或多個事件:BEFORE_START_ENVET, START_EVENT, AFTER_START_EVENT, BEFORE_STOP_EVENT, STOP_EVENT, AFTER)STOP_EVENT(共6個事件); 3)當組件啟動時,會觸發(fā)前3個事件;而當組件關(guān)閉時,會觸發(fā)后3個事件; 4)事件監(jiān)聽器:如果Catalina組件可以觸發(fā)事件,那么需要編寫相應(yīng)的事件監(jiān)聽器對這些事件進行響應(yīng)。事件監(jiān)聽器是 org.apache.catalina.LifecycleListener 接口的實例; 5)本文會介紹3個相關(guān)類:分別是 Lifecycle, LifecycleEvent, LifecycleListener;還外加一個工具類 LifecycleSupport,該類提供了一個簡單的方法來觸發(fā)某個組件的生命周期事件,并對事件監(jiān)聽器進行處理;
【1】Lifecycle接口(生命周期接口) 1)intro to Lifecycle:Catalina在設(shè)計上允許一個組件包含其他組件,以使得所有的組件都置于其父組件的監(jiān)護之下;這樣一來,Catalina的啟動類只需要啟動一個組件就可以將全部應(yīng)用的組件都啟動起來。這種單一啟動/關(guān)閉機制是通過 Lifecycle 接口來實現(xiàn)的;(干貨——Lifecycle接口的引入目的是:Catalina的啟動類只需要啟動一個組件就可以將全部應(yīng)用的組件都啟動起來)(干貨——單一啟動/關(guān)閉機制) public interface Lifecycle {public static final String START_EVENT = "start";public static final String BEFORE_START_EVENT = "before_start";public static final String AFTER_START_EVENT = "after_start";public static final String STOP_EVENT = "stop";public static final String BEFORE_STOP_EVENT = "before_stop"; public static final String AFTER_STOP_EVENT = "after_stop"; public void addLifecycleListener(LifecycleListener listener); public LifecycleListener[] findLifecycleListeners(); public void removeLifecycleListener(LifecycleListener listener); public void start() throws LifecycleException; public void stop() throws LifecycleException; } 【2】LifecycleEvent類(生命周期事件類) public final class LifecycleEvent extends EventObject { public LifecycleEvent(Lifecycle lifecycle, String type) {this(lifecycle, type, null);}public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {super(lifecycle);this.lifecycle = lifecycle;this.type = type;this.data = data;}private Object data = null;private Lifecycle lifecycle = null;private String type = null;public Object getData() {return (this.data);}public Lifecycle getLifecycle() {return (this.lifecycle);}public String getType() {return (this.type);} } 【3】LifecycleListener接口(生命周期事件監(jiān)聽器接口) 1)該接口只有一個方法:即?lifecycleEvent 方法,當某個事件監(jiān)聽器監(jiān)聽到相關(guān)事件發(fā)生時,會調(diào)用該方法; public interface LifecycleListener {public void lifecycleEvent(LifecycleEvent event);}【4】LifecycleSupport類 1)LifecycleSupport類:實現(xiàn)了 Lifecycle接口, 并且對某個事件注冊了監(jiān)聽器的組件必須提供 Lifecycle接口中3個與監(jiān)聽器相關(guān)的方法(分別是 addLifecycleListener(), findLifecycleListeners(), removeLifecycleListener())的實現(xiàn)。 2)然后,該組件需要將所有注冊的事件監(jiān)聽器存儲到一個數(shù)組,ArrayList 或其他類似的對象中。 3)Catalina提供了一個工具類——org.apache.catalina.util.LifecycleSupport:?來幫助組件管理監(jiān)聽器,并觸發(fā)相應(yīng)的生命周期事件; 4)LifecycleSupport類的定義如下: public final class LifecycleSupport {public LifecycleSupport(Lifecycle lifecycle) {super();this.lifecycle = lifecycle;}private Lifecycle lifecycle = null;private LifecycleListener listeners[] = new LifecycleListener[0];public void addLifecycleListener(LifecycleListener listener) { //添加生命周期事件監(jiān)聽器synchronized (listeners) {LifecycleListener results[] =new LifecycleListener[listeners.length + 1];for (int i = 0; i < listeners.length; i++)results[i] = listeners[i];results[listeners.length] = listener;listeners = results;}}public LifecycleListener[] findLifecycleListeners() {return listeners;}public void fireLifecycleEvent(String type, Object data) { // 觸發(fā)生命周期事件監(jiān)聽器LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);LifecycleListener interested[] = null;synchronized (listeners) {interested = (LifecycleListener[]) listeners.clone();}for (int i = 0; i < interested.length; i++)interested[i].lifecycleEvent(event);}public void removeLifecycleListener(LifecycleListener listener) { // 移除生命周期事件監(jiān)聽器synchronized (listeners) {int n = -1;for (int i = 0; i < listeners.length; i++) {if (listeners[i] == listener) {n = i;break;}}if (n < 0)return;LifecycleListener results[] =new LifecycleListener[listeners.length - 1];int j = 0;for (int i = 0; i < listeners.length; i++) {if (i != n)results[j++] = listeners[i];}listeners = results;}} } 5)添加和刪除事件監(jiān)聽器的方法(干貨——添加和刪除事件監(jiān)聽器的方法,其處理技巧非常重要,代碼如上) 5.1)添加事件監(jiān)聽器:當調(diào)用addLifecycleListener()方法添加一個事件監(jiān)聽器時,會創(chuàng)建一個新數(shù)組,大小為原數(shù)組的元素個數(shù)加1;然后將原數(shù)組中的所有元素copy到 新數(shù)組中,并將新的事件監(jiān)聽器添加到新數(shù)組中; 5.2)刪除事件監(jiān)聽器:當調(diào)用 removeLifecycleListener() 方法刪除一個事件監(jiān)聽器時,也會新建一個數(shù)組,大小為原數(shù)組的元素個數(shù)減1;然后將除了指定監(jiān)聽器外的其他所有監(jiān)聽器都copy到 新數(shù)組中; 6)觸發(fā)生命周期事件(fireLifecycleEvent()方法):會觸發(fā)一個生命周期事件。首先,它會copy 事件監(jiān)聽器數(shù)組,然后調(diào)用數(shù)組中每個成員的lifecycleEvent() 方法,并傳入要觸發(fā)的事件; public void fireLifecycleEvent(String type, Object data) {LifecycleEvent event = new LifecycleEvent(lifecycle, type, data); LifecycleListener interested[] = null;synchronized (listeners) {interested = (LifecycleListener[]) listeners.clone(); // step1}for (int i = 0; i < interested.length; i++)interested[i].lifecycleEvent(event); // step2}7)當要添加一個事件監(jiān)聽器時,SimpleContext實例 會調(diào)用LifecycleSupport類的 addLifecycleListener() 方法: // implementation of the Lifecycle interface's methodspublic void addLifecycleListener(LifecycleListener listener) {lifecycle.addLifecycleListener(listener);} 【5】應(yīng)用程序 【5.1】 SimpleContext類 1)SimpleContext類使用變量lifecycle 引用了一個 LifecycleSupport 實例: 2)SimpleContext的start方法和stop方法 public synchronized void start() throws LifecycleException { // SimpleContext.start()if (started)throw new LifecycleException("SimpleContext has already started");// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);started = true;try {// 啟動它的組件和子容器,當前程序中,共有兩個組件實現(xiàn)了Lifecycle接口,分別是// SimpleLoader類和 SimplePipeline類.// Start our subordinate components, if anyif ((loader != null) && (loader instanceof Lifecycle))((Lifecycle) loader).start(); // highlight line.// Start our child containers, if anyContainer children[] = findChildren();for (int i = 0; i < children.length; i++) {if (children[i] instanceof Lifecycle)((Lifecycle) children[i]).start(); // highlight line.}// Start the Valves in our pipeline (including the basic),// if anyif (pipeline instanceof Lifecycle)((Lifecycle) pipeline).start(); // highlight line.// Notify our interested LifecycleListeners// 組件和子容器都啟動完畢后,會觸發(fā)兩個事件:START_EVENT AND AFTER_START_EVENT.lifecycle.fireLifecycleEvent(START_EVENT, null);}catch (Exception e) {e.printStackTrace();}// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);}// stop方法 類似于上述的 start方法.public void stop() throws LifecycleException { // SimpleContext.stop() 方法if (!started)throw new LifecycleException("SimpleContext has not been started");// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);lifecycle.fireLifecycleEvent(STOP_EVENT, null);started = false;try {// Stop the Valves in our pipeline (including the basic), if anyif (pipeline instanceof Lifecycle) {((Lifecycle) pipeline).stop();}// Stop our child containers, if anyContainer children[] = findChildren();for (int i = 0; i < children.length; i++) {if (children[i] instanceof Lifecycle)((Lifecycle) children[i]).stop();}if ((loader != null) && (loader instanceof Lifecycle)) {((Lifecycle) loader).stop();}}catch (Exception e) {e.printStackTrace();}// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);} 3)problem+solution: 3.1)problem: problem1)start() 方法是如何將所有子容器,以及與之相關(guān)的組件,包括載入器,管道和映射器等,啟動起來的? problem2)又是如何關(guān)閉這些容器和組件的? 3.2)solution:就是使用前面提到的單一啟動/關(guān)閉機制;使用這種機制,只需要啟動最高層級的組件即可,其余組件會由各自的父組件去啟動。同樣,關(guān)閉這些組件時,也只需要關(guān)閉最高層級的組件即可;(干貨——單一啟動/關(guān)閉機制) 4)start() 方法的調(diào)用過程 step1)首先檢查組件是否已經(jīng)啟動 step2)觸發(fā)BEFORE_START_EVENT事件 step3)將started 設(shè)置為true,表明該組件已經(jīng)啟動了 step4)啟動start方法所在類的組件和子容器。當前應(yīng)用程序中,共有兩個組件實現(xiàn)了Lifecycle接口,分別是 SimpleLoader and SimplePipeline類。 step5)觸發(fā)兩個事件:START_EVENT and AFTER_START_EVENT; step6)觸發(fā) BEFORE_STOP_EVENT事件 和 STOP_EVENT事件,重置started 5)stop() 方法調(diào)用過程(與start方法類似) step1)關(guān)閉與它關(guān)聯(lián)的所有組件和 SimpleContext 實例的子容器; step2)觸發(fā) AFTER_STOP_EVENT 事件
【5.2】 SimpleContextLifecycleListener類(事件監(jiān)聽器的實現(xiàn)類) 1)其中的 lifecycleEvent() 方法:它僅僅輸出已觸發(fā)事件類型;
【5.3】SimpleLoader類(僅僅是返回類加載器,與以往的Loader不同的是,它實現(xiàn)了 Lifecycle接口) 1)該類的Lifecycle接口中各個方法的實現(xiàn)只是向console輸出字符串。重要的是, 通過實現(xiàn)Lifecycle接口, 啟動SimpleLoader實例的任務(wù)就可以由與其相關(guān)聯(lián)的servlet容器來完成了;
【5.4】SimplePipeline類(管道,管道包括多個閥,每個閥就是一個任務(wù),遍歷管道中的閥,就是挨個執(zhí)行任務(wù),基礎(chǔ)閥最后執(zhí)行)
【5.5】SimpleWrapper類(利用SimpleLoader返回的類加載器,加載并返回相應(yīng)的servlet) 1)該類實現(xiàn)了 Lifecycle接口,就可以由其父容器來啟動該實例。 2)參見其start方法(與SimpleContext類的start方法類似): public synchronized void start() throws LifecycleException { // SimpleWrapper.start()System.out.println("Starting Wrapper " + name);if (started)throw new LifecycleException("Wrapper already started");// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);started = true;// Start our subordinate components, if anyif ((loader != null) && (loader instanceof Lifecycle))((Lifecycle) loader).start();// Start the Valves in our pipeline (including the basic), if anyif (pipeline instanceof Lifecycle)((Lifecycle) pipeline).start();// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(START_EVENT, null);// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);} 3)參見其stop方法(比較有趣) 3.1)stop方法的調(diào)用steps as follows: step1)除了輸出一個簡單的字符串外,它還要調(diào)用servlet實例的destroy方法 step2)檢查Wrapper實例是否啟動 step3)觸發(fā)BEFORE_STOP_EVENT 和 STOP_EVENT事件,并重置started step4)關(guān)閉與其相關(guān)聯(lián)的載入器和管道組件 step5)最后, 觸發(fā) AFTER_STOP_EVENT事件 public void stop() throws LifecycleException { // SimpleWrapper.stop() 方法System.out.println("Stopping wrapper " + name);// Shut down our servlet instance (if it has been initialized)try {instance.destroy();}catch (Throwable t) {}instance = null;if (!started)throw new LifecycleException("Wrapper " + name + " not started");// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(STOP_EVENT, null);started = false;// Stop the Valves in our pipeline (including the basic), if anyif (pipeline instanceof Lifecycle) {((Lifecycle) pipeline).stop();}// Stop our subordinate components, if anyif ((loader != null) && (loader instanceof Lifecycle)) {((Lifecycle) loader).stop();}// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);}
【6】運行應(yīng)用程序 0)app startup public final class Bootstrap {public static void main(String[] args) {// 連接器,創(chuàng)建服務(wù)器套接字,維護HttpProcessor 對象池(stack)Connector connector = new HttpConnector(); // servlet最低級容器 Wrapper,用于封裝servlet,并提供類加載器,加載相應(yīng)的servletWrapper wrapper1 = new SimpleWrapper();wrapper1.setName("Primitive");wrapper1.setServletClass("servlet.PrimitiveServlet");Wrapper wrapper2 = new SimpleWrapper();wrapper2.setName("Modern");wrapper2.setServletClass("servlet.ModernServlet");// 將Wrapper容器添加到其父容器ContextContext context = new SimpleContext(); context.addChild(wrapper1);context.addChild(wrapper2);// 映射器Mapper,其作用是通過 請求路徑,如 http://localhost:8080/Modern;// 通過HttpProcessor.process() 方法解析reqeust,獲取 訪問絕對路徑 /Modern// 通過在映射器(的map方法)查找該路徑對應(yīng)的容器資源名稱(Modern)// 然后還是在其map方法中繼續(xù)通過容器名稱(Modern)映射到servlet名稱(servlet.ModernServlet)// 這樣才通過 /Modern 映射到對應(yīng)的servlet訪問路徑(加載路徑,以便類加載器加載)Mapper mapper = new SimpleContextMapper();mapper.setProtocol("http");// 添加生命周期監(jiān)聽器LifecycleListener listener = new SimpleContextLifecycleListener();((Lifecycle) context).addLifecycleListener(listener);context.addMapper(mapper);// 添加類加載器Loader loader = new SimpleLoader();context.setLoader(loader);// 添加servlet訪問路徑(資源路徑) 和 資源名稱的映射關(guān)系// context.addServletMapping(pattern, name);context.addServletMapping("/Primitive", "Primitive");context.addServletMapping("/Modern", "Modern");connector.setContainer(context);try {connector.initialize(); // 初始化,主要返回服務(wù)器套接字// 觸發(fā)生命周期事件(可以參考下面的測試用例調(diào)用過程示例圖)((Lifecycle) connector).start(); // highlight line.((Lifecycle) context).start(); // highlight line.// make the application wait until we press a key.System.in.read();((Lifecycle) context).stop(); // highlight line.}catch (Exception e) {e.printStackTrace();}/* try { // these are some code in tomcat(5)-servlet container.connector.initialize();connector.start();// make the application wait until we press a key.System.in.read();}*/} } Attention)習慣上,我還是總結(jié)了測試用例(生命周期,事件+監(jiān)聽器)的調(diào)用過程示例圖
對以上調(diào)用過程的分析(SimpleContext.start() 方法為起點的 Analysis) A1)容器:本應(yīng)用程序(Bootstrap.java)有兩種容器Wrapper 和 Context,實現(xiàn)類分別是 SimpleWrapper 和 SimpleContext;每種容器分別有 管道類(SimplePipeline),而管道類通過閥數(shù)組類封裝非基礎(chǔ)閥,和一個閥的實例來封裝基礎(chǔ)閥(基礎(chǔ)閥是可以手動設(shè)置的);即兩種容器Wrapper 和 Context 的管道是不同的,非基礎(chǔ)閥是不同的,當然基礎(chǔ)閥也是不同的;(干貨——理解到容器的概念非常重要,之后就是管道中的閥,非基礎(chǔ)閥和基礎(chǔ)閥,還有管道中閥的遍歷,最后遍歷基礎(chǔ)閥,這些都是曬干了很久的干貨); A2)SimpleContext.start()方法(第一張圖):通過生命周期實例(lifycycle,這在main方法中已經(jīng)設(shè)定了)調(diào)用fireLifecycleEvent()方法去觸發(fā)一個生命周期事件,這里觸發(fā)的是START_EVENT事件: step1)fireLifecycleEvent方法:創(chuàng)建生命周期事件,得到監(jiān)聽器數(shù)組的拷貝(多個監(jiān)聽器封裝在數(shù)組里面),依據(jù)監(jiān)聽器數(shù)組里面監(jiān)聽器list,挨個排的調(diào)用單個監(jiān)聽器的lifecycleEvent() step2)單個監(jiān)聽器實例:?是由SimpleContextLifecycleListener實例提供的,SimpleContextLifecycleListener.lifecycleEvent() 方法就打印一些對應(yīng)于 事件的info; step3)調(diào)用fireLifecycleEvent方法后,繼續(xù)調(diào)用findChildren()方法:首先要知道children 是一個封裝Wrapper類型的HashMap集合,在main方法中就已經(jīng)填充了children(鍵和值(鍵值對)分別是 Wrapper實例的名稱 和 Wrapper實例,而Wrapper負責加載servlet,并返回servlet);第二,findChildren會返回children對應(yīng)的Wrapper數(shù)組;第三,在for循環(huán)中,遍歷該數(shù)組,并調(diào)用單個Wrapper實例的start方法,轉(zhuǎn)向SimpleWrapper.start()方法; step4)SimpleWrapper.start()方法:?該方法和SimpleContext.start()方法有點類似,這里就省略了,因為SimpleWrapper ?和 SimpleContext都是容器,都實現(xiàn)了 Lifecycle 接口,所以它們的start方法類似,調(diào)用過程也是類似的,參見A2中對?SimpleContext.start()方法的描述;?(下圖所示)
1)運行參數(shù) E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src>java -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\webroot com.tomcat.chapter6.startup.B ootstrap HttpConnector Opening server socket on all host IP addresses HttpConnector[8080] Starting background thread SimpleContextLifecycleListener's event before_start Starting SimpleLoader Starting Wrapper Primitive Starting Wrapper Modern SimpleContextLifecycleListener's event start Starting context. SimpleContextLifecycleListener's event after_start ModernServlet -- init init from service SimpleContextLifecycleListener's event before_stop SimpleContextLifecycleListener's event stop Stopping context. Stopping wrapper Primitive destroy 2)運行結(jié)果
1)生命周期LifeCycle接口引入的背景:Catalina包含很多組件,當Catalina啟動或關(guān)閉時,這些組件也會啟動或關(guān)閉。而通過實現(xiàn) org.apache.catalina.Lifecyle接口,可以達到統(tǒng)一啟動或關(guān)閉這些組件的目的; 2)實現(xiàn)了Lifecycle接口的組件可以觸發(fā)一個或多個事件:BEFORE_START_ENVET, START_EVENT, AFTER_START_EVENT, BEFORE_STOP_EVENT, STOP_EVENT, AFTER)STOP_EVENT(共6個事件); 3)當組件啟動時,會觸發(fā)前3個事件;而當組件關(guān)閉時,會觸發(fā)后3個事件; 4)事件監(jiān)聽器:如果Catalina組件可以觸發(fā)事件,那么需要編寫相應(yīng)的事件監(jiān)聽器對這些事件進行響應(yīng)。事件監(jiān)聽器是 org.apache.catalina.LifecycleListener 接口的實例; 5)本文會介紹3個相關(guān)類:分別是 Lifecycle, LifecycleEvent, LifecycleListener;還外加一個工具類 LifecycleSupport,該類提供了一個簡單的方法來觸發(fā)某個組件的生命周期事件,并對事件監(jiān)聽器進行處理;
【1】Lifecycle接口(生命周期接口) 1)intro to Lifecycle:Catalina在設(shè)計上允許一個組件包含其他組件,以使得所有的組件都置于其父組件的監(jiān)護之下;這樣一來,Catalina的啟動類只需要啟動一個組件就可以將全部應(yīng)用的組件都啟動起來。這種單一啟動/關(guān)閉機制是通過 Lifecycle 接口來實現(xiàn)的;(干貨——Lifecycle接口的引入目的是:Catalina的啟動類只需要啟動一個組件就可以將全部應(yīng)用的組件都啟動起來)(干貨——單一啟動/關(guān)閉機制) public interface Lifecycle {public static final String START_EVENT = "start";public static final String BEFORE_START_EVENT = "before_start";public static final String AFTER_START_EVENT = "after_start";public static final String STOP_EVENT = "stop";public static final String BEFORE_STOP_EVENT = "before_stop"; public static final String AFTER_STOP_EVENT = "after_stop"; public void addLifecycleListener(LifecycleListener listener); public LifecycleListener[] findLifecycleListeners(); public void removeLifecycleListener(LifecycleListener listener); public void start() throws LifecycleException; public void stop() throws LifecycleException; } 【2】LifecycleEvent類(生命周期事件類) public final class LifecycleEvent extends EventObject { public LifecycleEvent(Lifecycle lifecycle, String type) {this(lifecycle, type, null);}public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {super(lifecycle);this.lifecycle = lifecycle;this.type = type;this.data = data;}private Object data = null;private Lifecycle lifecycle = null;private String type = null;public Object getData() {return (this.data);}public Lifecycle getLifecycle() {return (this.lifecycle);}public String getType() {return (this.type);} } 【3】LifecycleListener接口(生命周期事件監(jiān)聽器接口) 1)該接口只有一個方法:即?lifecycleEvent 方法,當某個事件監(jiān)聽器監(jiān)聽到相關(guān)事件發(fā)生時,會調(diào)用該方法; public interface LifecycleListener {public void lifecycleEvent(LifecycleEvent event);}【4】LifecycleSupport類 1)LifecycleSupport類:實現(xiàn)了 Lifecycle接口, 并且對某個事件注冊了監(jiān)聽器的組件必須提供 Lifecycle接口中3個與監(jiān)聽器相關(guān)的方法(分別是 addLifecycleListener(), findLifecycleListeners(), removeLifecycleListener())的實現(xiàn)。 2)然后,該組件需要將所有注冊的事件監(jiān)聽器存儲到一個數(shù)組,ArrayList 或其他類似的對象中。 3)Catalina提供了一個工具類——org.apache.catalina.util.LifecycleSupport:?來幫助組件管理監(jiān)聽器,并觸發(fā)相應(yīng)的生命周期事件; 4)LifecycleSupport類的定義如下: public final class LifecycleSupport {public LifecycleSupport(Lifecycle lifecycle) {super();this.lifecycle = lifecycle;}private Lifecycle lifecycle = null;private LifecycleListener listeners[] = new LifecycleListener[0];public void addLifecycleListener(LifecycleListener listener) { //添加生命周期事件監(jiān)聽器synchronized (listeners) {LifecycleListener results[] =new LifecycleListener[listeners.length + 1];for (int i = 0; i < listeners.length; i++)results[i] = listeners[i];results[listeners.length] = listener;listeners = results;}}public LifecycleListener[] findLifecycleListeners() {return listeners;}public void fireLifecycleEvent(String type, Object data) { // 觸發(fā)生命周期事件監(jiān)聽器LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);LifecycleListener interested[] = null;synchronized (listeners) {interested = (LifecycleListener[]) listeners.clone();}for (int i = 0; i < interested.length; i++)interested[i].lifecycleEvent(event);}public void removeLifecycleListener(LifecycleListener listener) { // 移除生命周期事件監(jiān)聽器synchronized (listeners) {int n = -1;for (int i = 0; i < listeners.length; i++) {if (listeners[i] == listener) {n = i;break;}}if (n < 0)return;LifecycleListener results[] =new LifecycleListener[listeners.length - 1];int j = 0;for (int i = 0; i < listeners.length; i++) {if (i != n)results[j++] = listeners[i];}listeners = results;}} } 5)添加和刪除事件監(jiān)聽器的方法(干貨——添加和刪除事件監(jiān)聽器的方法,其處理技巧非常重要,代碼如上) 5.1)添加事件監(jiān)聽器:當調(diào)用addLifecycleListener()方法添加一個事件監(jiān)聽器時,會創(chuàng)建一個新數(shù)組,大小為原數(shù)組的元素個數(shù)加1;然后將原數(shù)組中的所有元素copy到 新數(shù)組中,并將新的事件監(jiān)聽器添加到新數(shù)組中; 5.2)刪除事件監(jiān)聽器:當調(diào)用 removeLifecycleListener() 方法刪除一個事件監(jiān)聽器時,也會新建一個數(shù)組,大小為原數(shù)組的元素個數(shù)減1;然后將除了指定監(jiān)聽器外的其他所有監(jiān)聽器都copy到 新數(shù)組中; 6)觸發(fā)生命周期事件(fireLifecycleEvent()方法):會觸發(fā)一個生命周期事件。首先,它會copy 事件監(jiān)聽器數(shù)組,然后調(diào)用數(shù)組中每個成員的lifecycleEvent() 方法,并傳入要觸發(fā)的事件; public void fireLifecycleEvent(String type, Object data) {LifecycleEvent event = new LifecycleEvent(lifecycle, type, data); LifecycleListener interested[] = null;synchronized (listeners) {interested = (LifecycleListener[]) listeners.clone(); // step1}for (int i = 0; i < interested.length; i++)interested[i].lifecycleEvent(event); // step2}7)當要添加一個事件監(jiān)聽器時,SimpleContext實例 會調(diào)用LifecycleSupport類的 addLifecycleListener() 方法: // implementation of the Lifecycle interface's methodspublic void addLifecycleListener(LifecycleListener listener) {lifecycle.addLifecycleListener(listener);} 【5】應(yīng)用程序 【5.1】 SimpleContext類 1)SimpleContext類使用變量lifecycle 引用了一個 LifecycleSupport 實例: 2)SimpleContext的start方法和stop方法 public synchronized void start() throws LifecycleException { // SimpleContext.start()if (started)throw new LifecycleException("SimpleContext has already started");// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);started = true;try {// 啟動它的組件和子容器,當前程序中,共有兩個組件實現(xiàn)了Lifecycle接口,分別是// SimpleLoader類和 SimplePipeline類.// Start our subordinate components, if anyif ((loader != null) && (loader instanceof Lifecycle))((Lifecycle) loader).start(); // highlight line.// Start our child containers, if anyContainer children[] = findChildren();for (int i = 0; i < children.length; i++) {if (children[i] instanceof Lifecycle)((Lifecycle) children[i]).start(); // highlight line.}// Start the Valves in our pipeline (including the basic),// if anyif (pipeline instanceof Lifecycle)((Lifecycle) pipeline).start(); // highlight line.// Notify our interested LifecycleListeners// 組件和子容器都啟動完畢后,會觸發(fā)兩個事件:START_EVENT AND AFTER_START_EVENT.lifecycle.fireLifecycleEvent(START_EVENT, null);}catch (Exception e) {e.printStackTrace();}// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);}// stop方法 類似于上述的 start方法.public void stop() throws LifecycleException { // SimpleContext.stop() 方法if (!started)throw new LifecycleException("SimpleContext has not been started");// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);lifecycle.fireLifecycleEvent(STOP_EVENT, null);started = false;try {// Stop the Valves in our pipeline (including the basic), if anyif (pipeline instanceof Lifecycle) {((Lifecycle) pipeline).stop();}// Stop our child containers, if anyContainer children[] = findChildren();for (int i = 0; i < children.length; i++) {if (children[i] instanceof Lifecycle)((Lifecycle) children[i]).stop();}if ((loader != null) && (loader instanceof Lifecycle)) {((Lifecycle) loader).stop();}}catch (Exception e) {e.printStackTrace();}// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);} 3)problem+solution: 3.1)problem: problem1)start() 方法是如何將所有子容器,以及與之相關(guān)的組件,包括載入器,管道和映射器等,啟動起來的? problem2)又是如何關(guān)閉這些容器和組件的? 3.2)solution:就是使用前面提到的單一啟動/關(guān)閉機制;使用這種機制,只需要啟動最高層級的組件即可,其余組件會由各自的父組件去啟動。同樣,關(guān)閉這些組件時,也只需要關(guān)閉最高層級的組件即可;(干貨——單一啟動/關(guān)閉機制) 4)start() 方法的調(diào)用過程 step1)首先檢查組件是否已經(jīng)啟動 step2)觸發(fā)BEFORE_START_EVENT事件 step3)將started 設(shè)置為true,表明該組件已經(jīng)啟動了 step4)啟動start方法所在類的組件和子容器。當前應(yīng)用程序中,共有兩個組件實現(xiàn)了Lifecycle接口,分別是 SimpleLoader and SimplePipeline類。 step5)觸發(fā)兩個事件:START_EVENT and AFTER_START_EVENT; step6)觸發(fā) BEFORE_STOP_EVENT事件 和 STOP_EVENT事件,重置started 5)stop() 方法調(diào)用過程(與start方法類似) step1)關(guān)閉與它關(guān)聯(lián)的所有組件和 SimpleContext 實例的子容器; step2)觸發(fā) AFTER_STOP_EVENT 事件
【5.2】 SimpleContextLifecycleListener類(事件監(jiān)聽器的實現(xiàn)類) 1)其中的 lifecycleEvent() 方法:它僅僅輸出已觸發(fā)事件類型;
【5.3】SimpleLoader類(僅僅是返回類加載器,與以往的Loader不同的是,它實現(xiàn)了 Lifecycle接口) 1)該類的Lifecycle接口中各個方法的實現(xiàn)只是向console輸出字符串。重要的是, 通過實現(xiàn)Lifecycle接口, 啟動SimpleLoader實例的任務(wù)就可以由與其相關(guān)聯(lián)的servlet容器來完成了;
【5.4】SimplePipeline類(管道,管道包括多個閥,每個閥就是一個任務(wù),遍歷管道中的閥,就是挨個執(zhí)行任務(wù),基礎(chǔ)閥最后執(zhí)行)
【5.5】SimpleWrapper類(利用SimpleLoader返回的類加載器,加載并返回相應(yīng)的servlet) 1)該類實現(xiàn)了 Lifecycle接口,就可以由其父容器來啟動該實例。 2)參見其start方法(與SimpleContext類的start方法類似): public synchronized void start() throws LifecycleException { // SimpleWrapper.start()System.out.println("Starting Wrapper " + name);if (started)throw new LifecycleException("Wrapper already started");// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);started = true;// Start our subordinate components, if anyif ((loader != null) && (loader instanceof Lifecycle))((Lifecycle) loader).start();// Start the Valves in our pipeline (including the basic), if anyif (pipeline instanceof Lifecycle)((Lifecycle) pipeline).start();// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(START_EVENT, null);// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);} 3)參見其stop方法(比較有趣) 3.1)stop方法的調(diào)用steps as follows: step1)除了輸出一個簡單的字符串外,它還要調(diào)用servlet實例的destroy方法 step2)檢查Wrapper實例是否啟動 step3)觸發(fā)BEFORE_STOP_EVENT 和 STOP_EVENT事件,并重置started step4)關(guān)閉與其相關(guān)聯(lián)的載入器和管道組件 step5)最后, 觸發(fā) AFTER_STOP_EVENT事件 public void stop() throws LifecycleException { // SimpleWrapper.stop() 方法System.out.println("Stopping wrapper " + name);// Shut down our servlet instance (if it has been initialized)try {instance.destroy();}catch (Throwable t) {}instance = null;if (!started)throw new LifecycleException("Wrapper " + name + " not started");// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(STOP_EVENT, null);started = false;// Stop the Valves in our pipeline (including the basic), if anyif (pipeline instanceof Lifecycle) {((Lifecycle) pipeline).stop();}// Stop our subordinate components, if anyif ((loader != null) && (loader instanceof Lifecycle)) {((Lifecycle) loader).stop();}// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);}
【6】運行應(yīng)用程序 0)app startup public final class Bootstrap {public static void main(String[] args) {// 連接器,創(chuàng)建服務(wù)器套接字,維護HttpProcessor 對象池(stack)Connector connector = new HttpConnector(); // servlet最低級容器 Wrapper,用于封裝servlet,并提供類加載器,加載相應(yīng)的servletWrapper wrapper1 = new SimpleWrapper();wrapper1.setName("Primitive");wrapper1.setServletClass("servlet.PrimitiveServlet");Wrapper wrapper2 = new SimpleWrapper();wrapper2.setName("Modern");wrapper2.setServletClass("servlet.ModernServlet");// 將Wrapper容器添加到其父容器ContextContext context = new SimpleContext(); context.addChild(wrapper1);context.addChild(wrapper2);// 映射器Mapper,其作用是通過 請求路徑,如 http://localhost:8080/Modern;// 通過HttpProcessor.process() 方法解析reqeust,獲取 訪問絕對路徑 /Modern// 通過在映射器(的map方法)查找該路徑對應(yīng)的容器資源名稱(Modern)// 然后還是在其map方法中繼續(xù)通過容器名稱(Modern)映射到servlet名稱(servlet.ModernServlet)// 這樣才通過 /Modern 映射到對應(yīng)的servlet訪問路徑(加載路徑,以便類加載器加載)Mapper mapper = new SimpleContextMapper();mapper.setProtocol("http");// 添加生命周期監(jiān)聽器LifecycleListener listener = new SimpleContextLifecycleListener();((Lifecycle) context).addLifecycleListener(listener);context.addMapper(mapper);// 添加類加載器Loader loader = new SimpleLoader();context.setLoader(loader);// 添加servlet訪問路徑(資源路徑) 和 資源名稱的映射關(guān)系// context.addServletMapping(pattern, name);context.addServletMapping("/Primitive", "Primitive");context.addServletMapping("/Modern", "Modern");connector.setContainer(context);try {connector.initialize(); // 初始化,主要返回服務(wù)器套接字// 觸發(fā)生命周期事件(可以參考下面的測試用例調(diào)用過程示例圖)((Lifecycle) connector).start(); // highlight line.((Lifecycle) context).start(); // highlight line.// make the application wait until we press a key.System.in.read();((Lifecycle) context).stop(); // highlight line.}catch (Exception e) {e.printStackTrace();}/* try { // these are some code in tomcat(5)-servlet container.connector.initialize();connector.start();// make the application wait until we press a key.System.in.read();}*/} } Attention)習慣上,我還是總結(jié)了測試用例(生命周期,事件+監(jiān)聽器)的調(diào)用過程示例圖
對以上調(diào)用過程的分析(SimpleContext.start() 方法為起點的 Analysis) A1)容器:本應(yīng)用程序(Bootstrap.java)有兩種容器Wrapper 和 Context,實現(xiàn)類分別是 SimpleWrapper 和 SimpleContext;每種容器分別有 管道類(SimplePipeline),而管道類通過閥數(shù)組類封裝非基礎(chǔ)閥,和一個閥的實例來封裝基礎(chǔ)閥(基礎(chǔ)閥是可以手動設(shè)置的);即兩種容器Wrapper 和 Context 的管道是不同的,非基礎(chǔ)閥是不同的,當然基礎(chǔ)閥也是不同的;(干貨——理解到容器的概念非常重要,之后就是管道中的閥,非基礎(chǔ)閥和基礎(chǔ)閥,還有管道中閥的遍歷,最后遍歷基礎(chǔ)閥,這些都是曬干了很久的干貨); A2)SimpleContext.start()方法(第一張圖):通過生命周期實例(lifycycle,這在main方法中已經(jīng)設(shè)定了)調(diào)用fireLifecycleEvent()方法去觸發(fā)一個生命周期事件,這里觸發(fā)的是START_EVENT事件: step1)fireLifecycleEvent方法:創(chuàng)建生命周期事件,得到監(jiān)聽器數(shù)組的拷貝(多個監(jiān)聽器封裝在數(shù)組里面),依據(jù)監(jiān)聽器數(shù)組里面監(jiān)聽器list,挨個排的調(diào)用單個監(jiān)聽器的lifecycleEvent() step2)單個監(jiān)聽器實例:?是由SimpleContextLifecycleListener實例提供的,SimpleContextLifecycleListener.lifecycleEvent() 方法就打印一些對應(yīng)于 事件的info; step3)調(diào)用fireLifecycleEvent方法后,繼續(xù)調(diào)用findChildren()方法:首先要知道children 是一個封裝Wrapper類型的HashMap集合,在main方法中就已經(jīng)填充了children(鍵和值(鍵值對)分別是 Wrapper實例的名稱 和 Wrapper實例,而Wrapper負責加載servlet,并返回servlet);第二,findChildren會返回children對應(yīng)的Wrapper數(shù)組;第三,在for循環(huán)中,遍歷該數(shù)組,并調(diào)用單個Wrapper實例的start方法,轉(zhuǎn)向SimpleWrapper.start()方法; step4)SimpleWrapper.start()方法:?該方法和SimpleContext.start()方法有點類似,這里就省略了,因為SimpleWrapper ?和 SimpleContext都是容器,都實現(xiàn)了 Lifecycle 接口,所以它們的start方法類似,調(diào)用過程也是類似的,參見A2中對?SimpleContext.start()方法的描述;?(下圖所示)
1)運行參數(shù) E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src>java -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\webroot com.tomcat.chapter6.startup.B ootstrap HttpConnector Opening server socket on all host IP addresses HttpConnector[8080] Starting background thread SimpleContextLifecycleListener's event before_start Starting SimpleLoader Starting Wrapper Primitive Starting Wrapper Modern SimpleContextLifecycleListener's event start Starting context. SimpleContextLifecycleListener's event after_start ModernServlet -- init init from service SimpleContextLifecycleListener's event before_stop SimpleContextLifecycleListener's event stop Stopping context. Stopping wrapper Primitive destroy 2)運行結(jié)果
總結(jié)
以上是生活随笔為你收集整理的tomcat(6)生命周期的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 刑侦破案电视剧推荐(好看的刑侦悬疑电视剧
- 下一篇: 哈儿小波分解和重构(降维和升维)实现算法