tomcat(6)生命周期
生活随笔
收集整理的這篇文章主要介紹了
tomcat(6)生命周期
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【0】README
0.1)本文部分文字描述轉自“深入剖析tomcat”,旨在學習 “tomcat生命周期” 的基礎知識;
0.2)for source code, please visit ?https://github.com/pacosonTang/HowTomcatWorks/tree/master/chapter6?
0.3)溫馨建議:建議閱讀本文之前,已閱讀過 tomcat(1~5)的系列文章,因為它們是環環相扣的;
1)生命周期LifeCycle接口引入的背景:Catalina包含很多組件,當Catalina啟動或關閉時,這些組件也會啟動或關閉。而通過實現 org.apache.catalina.Lifecyle接口,可以達到統一啟動或關閉這些組件的目的; 2)實現了Lifecycle接口的組件可以觸發一個或多個事件:BEFORE_START_ENVET, START_EVENT, AFTER_START_EVENT, BEFORE_STOP_EVENT, STOP_EVENT, AFTER)STOP_EVENT(共6個事件); 3)當組件啟動時,會觸發前3個事件;而當組件關閉時,會觸發后3個事件; 4)事件監聽器:如果Catalina組件可以觸發事件,那么需要編寫相應的事件監聽器對這些事件進行響應。事件監聽器是 org.apache.catalina.LifecycleListener 接口的實例; 5)本文會介紹3個相關類:分別是 Lifecycle, LifecycleEvent, LifecycleListener;還外加一個工具類 LifecycleSupport,該類提供了一個簡單的方法來觸發某個組件的生命周期事件,并對事件監聽器進行處理;
【1】Lifecycle接口(生命周期接口) 1)intro to Lifecycle:Catalina在設計上允許一個組件包含其他組件,以使得所有的組件都置于其父組件的監護之下;這樣一來,Catalina的啟動類只需要啟動一個組件就可以將全部應用的組件都啟動起來。這種單一啟動/關閉機制是通過 Lifecycle 接口來實現的;(干貨——Lifecycle接口的引入目的是:Catalina的啟動類只需要啟動一個組件就可以將全部應用的組件都啟動起來)(干貨——單一啟動/關閉機制) 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接口(生命周期事件監聽器接口) 1)該接口只有一個方法:即?lifecycleEvent 方法,當某個事件監聽器監聽到相關事件發生時,會調用該方法; public interface LifecycleListener {public void lifecycleEvent(LifecycleEvent event);}【4】LifecycleSupport類 1)LifecycleSupport類:實現了 Lifecycle接口, 并且對某個事件注冊了監聽器的組件必須提供 Lifecycle接口中3個與監聽器相關的方法(分別是 addLifecycleListener(), findLifecycleListeners(), removeLifecycleListener())的實現。 2)然后,該組件需要將所有注冊的事件監聽器存儲到一個數組,ArrayList 或其他類似的對象中。 3)Catalina提供了一個工具類——org.apache.catalina.util.LifecycleSupport:?來幫助組件管理監聽器,并觸發相應的生命周期事件; 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) { //添加生命周期事件監聽器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) { // 觸發生命周期事件監聽器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) { // 移除生命周期事件監聽器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)添加和刪除事件監聽器的方法(干貨——添加和刪除事件監聽器的方法,其處理技巧非常重要,代碼如上) 5.1)添加事件監聽器:當調用addLifecycleListener()方法添加一個事件監聽器時,會創建一個新數組,大小為原數組的元素個數加1;然后將原數組中的所有元素copy到 新數組中,并將新的事件監聽器添加到新數組中; 5.2)刪除事件監聽器:當調用 removeLifecycleListener() 方法刪除一個事件監聽器時,也會新建一個數組,大小為原數組的元素個數減1;然后將除了指定監聽器外的其他所有監聽器都copy到 新數組中; 6)觸發生命周期事件(fireLifecycleEvent()方法):會觸發一個生命周期事件。首先,它會copy 事件監聽器數組,然后調用數組中每個成員的lifecycleEvent() 方法,并傳入要觸發的事件; 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)當要添加一個事件監聽器時,SimpleContext實例 會調用LifecycleSupport類的 addLifecycleListener() 方法: // implementation of the Lifecycle interface's methodspublic void addLifecycleListener(LifecycleListener listener) {lifecycle.addLifecycleListener(listener);} 【5】應用程序 【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 {// 啟動它的組件和子容器,當前程序中,共有兩個組件實現了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// 組件和子容器都啟動完畢后,會觸發兩個事件: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() 方法是如何將所有子容器,以及與之相關的組件,包括載入器,管道和映射器等,啟動起來的? problem2)又是如何關閉這些容器和組件的? 3.2)solution:就是使用前面提到的單一啟動/關閉機制;使用這種機制,只需要啟動最高層級的組件即可,其余組件會由各自的父組件去啟動。同樣,關閉這些組件時,也只需要關閉最高層級的組件即可;(干貨——單一啟動/關閉機制) 4)start() 方法的調用過程 step1)首先檢查組件是否已經啟動 step2)觸發BEFORE_START_EVENT事件 step3)將started 設置為true,表明該組件已經啟動了 step4)啟動start方法所在類的組件和子容器。當前應用程序中,共有兩個組件實現了Lifecycle接口,分別是 SimpleLoader and SimplePipeline類。 step5)觸發兩個事件:START_EVENT and AFTER_START_EVENT; step6)觸發 BEFORE_STOP_EVENT事件 和 STOP_EVENT事件,重置started 5)stop() 方法調用過程(與start方法類似) step1)關閉與它關聯的所有組件和 SimpleContext 實例的子容器; step2)觸發 AFTER_STOP_EVENT 事件
【5.2】 SimpleContextLifecycleListener類(事件監聽器的實現類) 1)其中的 lifecycleEvent() 方法:它僅僅輸出已觸發事件類型;
【5.3】SimpleLoader類(僅僅是返回類加載器,與以往的Loader不同的是,它實現了 Lifecycle接口) 1)該類的Lifecycle接口中各個方法的實現只是向console輸出字符串。重要的是, 通過實現Lifecycle接口, 啟動SimpleLoader實例的任務就可以由與其相關聯的servlet容器來完成了;
【5.4】SimplePipeline類(管道,管道包括多個閥,每個閥就是一個任務,遍歷管道中的閥,就是挨個執行任務,基礎閥最后執行)
【5.5】SimpleWrapper類(利用SimpleLoader返回的類加載器,加載并返回相應的servlet) 1)該類實現了 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方法的調用steps as follows: step1)除了輸出一個簡單的字符串外,它還要調用servlet實例的destroy方法 step2)檢查Wrapper實例是否啟動 step3)觸發BEFORE_STOP_EVENT 和 STOP_EVENT事件,并重置started step4)關閉與其相關聯的載入器和管道組件 step5)最后, 觸發 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】運行應用程序 0)app startup public final class Bootstrap {public static void main(String[] args) {// 連接器,創建服務器套接字,維護HttpProcessor 對象池(stack)Connector connector = new HttpConnector(); // servlet最低級容器 Wrapper,用于封裝servlet,并提供類加載器,加載相應的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方法)查找該路徑對應的容器資源名稱(Modern)// 然后還是在其map方法中繼續通過容器名稱(Modern)映射到servlet名稱(servlet.ModernServlet)// 這樣才通過 /Modern 映射到對應的servlet訪問路徑(加載路徑,以便類加載器加載)Mapper mapper = new SimpleContextMapper();mapper.setProtocol("http");// 添加生命周期監聽器LifecycleListener listener = new SimpleContextLifecycleListener();((Lifecycle) context).addLifecycleListener(listener);context.addMapper(mapper);// 添加類加載器Loader loader = new SimpleLoader();context.setLoader(loader);// 添加servlet訪問路徑(資源路徑) 和 資源名稱的映射關系// context.addServletMapping(pattern, name);context.addServletMapping("/Primitive", "Primitive");context.addServletMapping("/Modern", "Modern");connector.setContainer(context);try {connector.initialize(); // 初始化,主要返回服務器套接字// 觸發生命周期事件(可以參考下面的測試用例調用過程示例圖)((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)習慣上,我還是總結了測試用例(生命周期,事件+監聽器)的調用過程示例圖
對以上調用過程的分析(SimpleContext.start() 方法為起點的 Analysis) A1)容器:本應用程序(Bootstrap.java)有兩種容器Wrapper 和 Context,實現類分別是 SimpleWrapper 和 SimpleContext;每種容器分別有 管道類(SimplePipeline),而管道類通過閥數組類封裝非基礎閥,和一個閥的實例來封裝基礎閥(基礎閥是可以手動設置的);即兩種容器Wrapper 和 Context 的管道是不同的,非基礎閥是不同的,當然基礎閥也是不同的;(干貨——理解到容器的概念非常重要,之后就是管道中的閥,非基礎閥和基礎閥,還有管道中閥的遍歷,最后遍歷基礎閥,這些都是曬干了很久的干貨); A2)SimpleContext.start()方法(第一張圖):通過生命周期實例(lifycycle,這在main方法中已經設定了)調用fireLifecycleEvent()方法去觸發一個生命周期事件,這里觸發的是START_EVENT事件: step1)fireLifecycleEvent方法:創建生命周期事件,得到監聽器數組的拷貝(多個監聽器封裝在數組里面),依據監聽器數組里面監聽器list,挨個排的調用單個監聽器的lifecycleEvent() step2)單個監聽器實例:?是由SimpleContextLifecycleListener實例提供的,SimpleContextLifecycleListener.lifecycleEvent() 方法就打印一些對應于 事件的info; step3)調用fireLifecycleEvent方法后,繼續調用findChildren()方法:首先要知道children 是一個封裝Wrapper類型的HashMap集合,在main方法中就已經填充了children(鍵和值(鍵值對)分別是 Wrapper實例的名稱 和 Wrapper實例,而Wrapper負責加載servlet,并返回servlet);第二,findChildren會返回children對應的Wrapper數組;第三,在for循環中,遍歷該數組,并調用單個Wrapper實例的start方法,轉向SimpleWrapper.start()方法; step4)SimpleWrapper.start()方法:?該方法和SimpleContext.start()方法有點類似,這里就省略了,因為SimpleWrapper ?和 SimpleContext都是容器,都實現了 Lifecycle 接口,所以它們的start方法類似,調用過程也是類似的,參見A2中對?SimpleContext.start()方法的描述;?(下圖所示)
1)運行參數 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)運行結果
1)生命周期LifeCycle接口引入的背景:Catalina包含很多組件,當Catalina啟動或關閉時,這些組件也會啟動或關閉。而通過實現 org.apache.catalina.Lifecyle接口,可以達到統一啟動或關閉這些組件的目的; 2)實現了Lifecycle接口的組件可以觸發一個或多個事件:BEFORE_START_ENVET, START_EVENT, AFTER_START_EVENT, BEFORE_STOP_EVENT, STOP_EVENT, AFTER)STOP_EVENT(共6個事件); 3)當組件啟動時,會觸發前3個事件;而當組件關閉時,會觸發后3個事件; 4)事件監聽器:如果Catalina組件可以觸發事件,那么需要編寫相應的事件監聽器對這些事件進行響應。事件監聽器是 org.apache.catalina.LifecycleListener 接口的實例; 5)本文會介紹3個相關類:分別是 Lifecycle, LifecycleEvent, LifecycleListener;還外加一個工具類 LifecycleSupport,該類提供了一個簡單的方法來觸發某個組件的生命周期事件,并對事件監聽器進行處理;
【1】Lifecycle接口(生命周期接口) 1)intro to Lifecycle:Catalina在設計上允許一個組件包含其他組件,以使得所有的組件都置于其父組件的監護之下;這樣一來,Catalina的啟動類只需要啟動一個組件就可以將全部應用的組件都啟動起來。這種單一啟動/關閉機制是通過 Lifecycle 接口來實現的;(干貨——Lifecycle接口的引入目的是:Catalina的啟動類只需要啟動一個組件就可以將全部應用的組件都啟動起來)(干貨——單一啟動/關閉機制) 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接口(生命周期事件監聽器接口) 1)該接口只有一個方法:即?lifecycleEvent 方法,當某個事件監聽器監聽到相關事件發生時,會調用該方法; public interface LifecycleListener {public void lifecycleEvent(LifecycleEvent event);}【4】LifecycleSupport類 1)LifecycleSupport類:實現了 Lifecycle接口, 并且對某個事件注冊了監聽器的組件必須提供 Lifecycle接口中3個與監聽器相關的方法(分別是 addLifecycleListener(), findLifecycleListeners(), removeLifecycleListener())的實現。 2)然后,該組件需要將所有注冊的事件監聽器存儲到一個數組,ArrayList 或其他類似的對象中。 3)Catalina提供了一個工具類——org.apache.catalina.util.LifecycleSupport:?來幫助組件管理監聽器,并觸發相應的生命周期事件; 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) { //添加生命周期事件監聽器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) { // 觸發生命周期事件監聽器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) { // 移除生命周期事件監聽器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)添加和刪除事件監聽器的方法(干貨——添加和刪除事件監聽器的方法,其處理技巧非常重要,代碼如上) 5.1)添加事件監聽器:當調用addLifecycleListener()方法添加一個事件監聽器時,會創建一個新數組,大小為原數組的元素個數加1;然后將原數組中的所有元素copy到 新數組中,并將新的事件監聽器添加到新數組中; 5.2)刪除事件監聽器:當調用 removeLifecycleListener() 方法刪除一個事件監聽器時,也會新建一個數組,大小為原數組的元素個數減1;然后將除了指定監聽器外的其他所有監聽器都copy到 新數組中; 6)觸發生命周期事件(fireLifecycleEvent()方法):會觸發一個生命周期事件。首先,它會copy 事件監聽器數組,然后調用數組中每個成員的lifecycleEvent() 方法,并傳入要觸發的事件; 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)當要添加一個事件監聽器時,SimpleContext實例 會調用LifecycleSupport類的 addLifecycleListener() 方法: // implementation of the Lifecycle interface's methodspublic void addLifecycleListener(LifecycleListener listener) {lifecycle.addLifecycleListener(listener);} 【5】應用程序 【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 {// 啟動它的組件和子容器,當前程序中,共有兩個組件實現了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// 組件和子容器都啟動完畢后,會觸發兩個事件: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() 方法是如何將所有子容器,以及與之相關的組件,包括載入器,管道和映射器等,啟動起來的? problem2)又是如何關閉這些容器和組件的? 3.2)solution:就是使用前面提到的單一啟動/關閉機制;使用這種機制,只需要啟動最高層級的組件即可,其余組件會由各自的父組件去啟動。同樣,關閉這些組件時,也只需要關閉最高層級的組件即可;(干貨——單一啟動/關閉機制) 4)start() 方法的調用過程 step1)首先檢查組件是否已經啟動 step2)觸發BEFORE_START_EVENT事件 step3)將started 設置為true,表明該組件已經啟動了 step4)啟動start方法所在類的組件和子容器。當前應用程序中,共有兩個組件實現了Lifecycle接口,分別是 SimpleLoader and SimplePipeline類。 step5)觸發兩個事件:START_EVENT and AFTER_START_EVENT; step6)觸發 BEFORE_STOP_EVENT事件 和 STOP_EVENT事件,重置started 5)stop() 方法調用過程(與start方法類似) step1)關閉與它關聯的所有組件和 SimpleContext 實例的子容器; step2)觸發 AFTER_STOP_EVENT 事件
【5.2】 SimpleContextLifecycleListener類(事件監聽器的實現類) 1)其中的 lifecycleEvent() 方法:它僅僅輸出已觸發事件類型;
【5.3】SimpleLoader類(僅僅是返回類加載器,與以往的Loader不同的是,它實現了 Lifecycle接口) 1)該類的Lifecycle接口中各個方法的實現只是向console輸出字符串。重要的是, 通過實現Lifecycle接口, 啟動SimpleLoader實例的任務就可以由與其相關聯的servlet容器來完成了;
【5.4】SimplePipeline類(管道,管道包括多個閥,每個閥就是一個任務,遍歷管道中的閥,就是挨個執行任務,基礎閥最后執行)
【5.5】SimpleWrapper類(利用SimpleLoader返回的類加載器,加載并返回相應的servlet) 1)該類實現了 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方法的調用steps as follows: step1)除了輸出一個簡單的字符串外,它還要調用servlet實例的destroy方法 step2)檢查Wrapper實例是否啟動 step3)觸發BEFORE_STOP_EVENT 和 STOP_EVENT事件,并重置started step4)關閉與其相關聯的載入器和管道組件 step5)最后, 觸發 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】運行應用程序 0)app startup public final class Bootstrap {public static void main(String[] args) {// 連接器,創建服務器套接字,維護HttpProcessor 對象池(stack)Connector connector = new HttpConnector(); // servlet最低級容器 Wrapper,用于封裝servlet,并提供類加載器,加載相應的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方法)查找該路徑對應的容器資源名稱(Modern)// 然后還是在其map方法中繼續通過容器名稱(Modern)映射到servlet名稱(servlet.ModernServlet)// 這樣才通過 /Modern 映射到對應的servlet訪問路徑(加載路徑,以便類加載器加載)Mapper mapper = new SimpleContextMapper();mapper.setProtocol("http");// 添加生命周期監聽器LifecycleListener listener = new SimpleContextLifecycleListener();((Lifecycle) context).addLifecycleListener(listener);context.addMapper(mapper);// 添加類加載器Loader loader = new SimpleLoader();context.setLoader(loader);// 添加servlet訪問路徑(資源路徑) 和 資源名稱的映射關系// context.addServletMapping(pattern, name);context.addServletMapping("/Primitive", "Primitive");context.addServletMapping("/Modern", "Modern");connector.setContainer(context);try {connector.initialize(); // 初始化,主要返回服務器套接字// 觸發生命周期事件(可以參考下面的測試用例調用過程示例圖)((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)習慣上,我還是總結了測試用例(生命周期,事件+監聽器)的調用過程示例圖
對以上調用過程的分析(SimpleContext.start() 方法為起點的 Analysis) A1)容器:本應用程序(Bootstrap.java)有兩種容器Wrapper 和 Context,實現類分別是 SimpleWrapper 和 SimpleContext;每種容器分別有 管道類(SimplePipeline),而管道類通過閥數組類封裝非基礎閥,和一個閥的實例來封裝基礎閥(基礎閥是可以手動設置的);即兩種容器Wrapper 和 Context 的管道是不同的,非基礎閥是不同的,當然基礎閥也是不同的;(干貨——理解到容器的概念非常重要,之后就是管道中的閥,非基礎閥和基礎閥,還有管道中閥的遍歷,最后遍歷基礎閥,這些都是曬干了很久的干貨); A2)SimpleContext.start()方法(第一張圖):通過生命周期實例(lifycycle,這在main方法中已經設定了)調用fireLifecycleEvent()方法去觸發一個生命周期事件,這里觸發的是START_EVENT事件: step1)fireLifecycleEvent方法:創建生命周期事件,得到監聽器數組的拷貝(多個監聽器封裝在數組里面),依據監聽器數組里面監聽器list,挨個排的調用單個監聽器的lifecycleEvent() step2)單個監聽器實例:?是由SimpleContextLifecycleListener實例提供的,SimpleContextLifecycleListener.lifecycleEvent() 方法就打印一些對應于 事件的info; step3)調用fireLifecycleEvent方法后,繼續調用findChildren()方法:首先要知道children 是一個封裝Wrapper類型的HashMap集合,在main方法中就已經填充了children(鍵和值(鍵值對)分別是 Wrapper實例的名稱 和 Wrapper實例,而Wrapper負責加載servlet,并返回servlet);第二,findChildren會返回children對應的Wrapper數組;第三,在for循環中,遍歷該數組,并調用單個Wrapper實例的start方法,轉向SimpleWrapper.start()方法; step4)SimpleWrapper.start()方法:?該方法和SimpleContext.start()方法有點類似,這里就省略了,因為SimpleWrapper ?和 SimpleContext都是容器,都實現了 Lifecycle 接口,所以它們的start方法類似,調用過程也是類似的,參見A2中對?SimpleContext.start()方法的描述;?(下圖所示)
1)運行參數 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)運行結果
總結
以上是生活随笔為你收集整理的tomcat(6)生命周期的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 刑侦破案电视剧推荐(好看的刑侦悬疑电视剧
- 下一篇: 哈儿小波分解和重构(降维和升维)实现算法