1. 程式人生 > >【高軟作業4】:Tomcat 觀察者模式解析 之 Lifecycle 五分鐘讀懂UML類圖

【高軟作業4】:Tomcat 觀察者模式解析 之 Lifecycle 五分鐘讀懂UML類圖

一. 預備

  1. 如果你是Windows使用者,使用Eclipse,並且想自行匯入原始碼進行分析,你可能需要:Eclipse 匯入 Tomcat 原始碼
  2. 如果你已遺忘 觀察者模式,那麼你可以通過該文章回顧:設計模式(五)觀察者模式
  3. 如果你已遺忘 UML類圖相關知識,那麼你可以通過文章 (五分鐘讀懂UML類圖 )快速回顧

二. 啟程

1. Tomcat元件生命週期

Tomcat中包含多種元件,每個元件有各自的生命週期,而每個生命週期中又包含多種狀態,這些狀態會根據程式的執行而相互轉換,在這個過程中,某些元件會隨之做出相應的反饋。

下面是Tomcat元件生命週期狀態轉換圖,來自tomcat原始碼Lifecycle.java的註釋:

https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/Lifecycle.java

2. Lifecycle中的觀察者模式

生命週期的狀態改變,某些元件會隨之做出相應的反饋,該運作模式符合觀察者模式的應用範圍。下面是Tomcat中關於Lifecycle的觀察者模式類圖:

(為了描述方便,我對類的成員進行簡化,只給出文章講解會用到的成員;如果圖片看不清,滑鼠右鍵->檢視影象,Firefox是這樣的)

 3. 實現原理

我們通過 init() 方法的執行過程來看 Lifecycle 觀察者模式的實現原理。

  • Lifecycle subject; // 生命週期(主題)
  • LifecycleListener observer; // 觀察者
  • subject.addLifecycleListener(observer); // 主題將觀察者新增到觀察者列表(觀察者註冊)
  • subject.init(); // 生命週期狀態 NEW ----> INITIALIZED

在 生命週期狀態 由 NEW 轉到 INITIALIZED 的過程中,subject 會以 LifecycleEvent 為媒介來通知 observer,說:“我的狀態已經改變,你可以執行相關的操作了”,以 LifecycleBase

的實現為例,如下:

 1 @Override
 2 public final synchronized void init() throws LifecycleException {
 3     if (!state.equals(LifecycleState.NEW)) {
 4         invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
 5     }
 6 
 7     try {
 8         setStateInternal(LifecycleState.INITIALIZING, null, false);
 9         initInternal();
10         setStateInternal(LifecycleState.INITIALIZED, null, false);
11     } catch (Throwable t) {
12         handleSubClassException(t, "lifecycleBase.initFail", toString());
13     }
14 }
View Code
  • subject.init()
    • setStateInternal(LifecycleState.INITIALIZING, null, false); // 設定當前狀態為 INITIALIZING,並通知 observer,說:“我現在的狀態變成了 INITIALIZING,你可以執行相應操作了”
    • initInternal(); // 內部初始化(模版方法)
    • setStateInternal(LifecycleState.INITIALIZED, null, false); // 設定當前狀態為 INITIALIZED,並通知 observer,說:“我現在狀態改為 INITIALIZED,你可以執行相應操作了”

來看 LifecycleBase 中的 setStateInternal(LifecycleState state, Object data, boolean check) 內部是如何實現的吧(主要看最後面幾行),原始碼如下:

 1 private synchronized void setStateInternal(LifecycleState state, Object data, boolean check)
 2             throws LifecycleException {
 3     if (log.isDebugEnabled()) {
 4         log.debug(sm.getString("lifecycleBase.setState", this, state));
 5     }
 6 
 7     if (check) {
 8         // Must have been triggered by one of the abstract methods (assume
 9         // code in this class is correct)
10         // null is never a valid state
11         if (state == null) {
12             invalidTransition("null");
13             // Unreachable code - here to stop eclipse complaining about
14             // a possible NPE further down the method
15             return;
16         }
17 
18         // Any method can transition to failed
19         // startInternal() permits STARTING_PREP to STARTING
20         // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to
21         // STOPPING
22         if (!(state == LifecycleState.FAILED ||
23                 (this.state == LifecycleState.STARTING_PREP &&
24                         state == LifecycleState.STARTING) ||
25                 (this.state == LifecycleState.STOPPING_PREP &&
26                         state == LifecycleState.STOPPING) ||
27                 (this.state == LifecycleState.FAILED &&
28                         state == LifecycleState.STOPPING))) {
29             // No other transition permitted
30             invalidTransition(state.name());
31         }
32     }
33 
34     this.state = state;
35     String lifecycleEvent = state.getLifecycleEvent();
36     if (lifecycleEvent != null) {
37         fireLifecycleEvent(lifecycleEvent, data);
38     }
39 }
View Code
  • "你可以執行相應操作了",並不是在 observer 端執行操作,而是 subject 通過 observer 提供的介面 lifecycleEvent(LifecycleEvent event) 來執行操作
  • subject 通過呼叫其內部方法 fireLifecycleEvent(String type, Object data) 會被setStateInternal(...)方法呼叫)使其觀察者的方法 lifecycleEvent(LifecycleEvent event) 得到執行,從而達到訊息專遞的目的

以下是 LifecycleBase 中的 fireLifecycleEvent(String type, Object data)  的內部實現,以及 UserConfig 中的 lifecycleEvent(LifecycleEvent event) 內部實現,原始碼如下:

 1 // LifecycleBase.java
 2 /**
 3  * Allow sub classes to fire {@link Lifecycle} events.
 4  *
 5  * @param type  Event type
 6  * @param data  Data associated with event.
 7  */
 8 protected void fireLifecycleEvent(String type, Object data) {
 9     LifecycleEvent event = new LifecycleEvent(this, type, data);
10     for (LifecycleListener listener : lifecycleListeners) {
11         listener.lifecycleEvent(event);
12     }
13 }
14 
15 // UserConfig.java
16 /**
17  * Process the START event for an associated Host.
18  *
19  * @param event The lifecycle event that has occurred
20  */
21 @Override
22 public void lifecycleEvent(LifecycleEvent event) {
23 
24     // Identify the host we are associated with
25     try {
26         host = (Host) event.getLifecycle();
27     } catch (ClassCastException e) {
28         log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
29         return;
30     }
31 
32     // Process the event that has occurred
33     if (event.getType().equals(Lifecycle.START_EVENT))
34         start();
35     else if (event.getType().equals(Lifecycle.STOP_EVENT))
36         stop();
37 }
View Code
  • 至此,流程:“subject 註冊 observer --> subject 狀態改變 --> observer 做出相應的反饋 結束

三. 結束

觀察者模式給 Tomcat 生命週期管理帶來的好處:

  • 解除 生命週期 依賴生命週期元件 的耦合,讓雙方都依賴於各自的抽象,使得各自內部實現的變化不會影響到另一方
  • 通過介面呼叫,增加了程式設計的靈活性和可擴充套件性,雙方都可根據需要來擴充套件自己的子類,只要該子類按要求實現了相關介面方法就行
  • 支援一對多的 訊息專遞 / 事件響應,即:某個事物的狀態改變,會使依賴該事物的其他多個事物 收到訊息 / 做出反饋

本文所涉及的Java原始碼地址:

 轉載請說明出處!have a good time :D