tomcat事件處理機制

最近在閱讀“how tomcat works”這本書,結合tomcat7的源碼進行學習。對於學習的收穫,將通過“tomcat學習系列”記錄下來,和大家一起分享和交流,也算對自己學習的一種促進。閒話不多說,正文開始。

Catalina內部由多個組件組成,啓動時各個組件都需要啓動,關閉時需要各個組件關閉。如何協作各個組件的初始化、啓動、停止、銷燬等的一致性,通過各組件實現Lifecycle這個接口來完成。各組件在啓動、關閉等重要生命週期中,會發出事件通知,通知已註冊的觀察者做事件處理。

一、主要類圖


二、主要類介紹

1) Lifecycle

Lifecycle定義了組件生命週期中的通用事件(START_EVENT、STOP_EVENT等)和接口(start、stop、destroy、addLifecycleListener、removeLifecycleListener等)。組件可以通過實現Lifecyecle接口,完成組建的重要生命週期實現和組建的觀察者管理。

2)LifecycleState

定義了組件生命週期中的狀態和狀態對應的事件。當狀態發生改變時,會發出相應事件,通知觀察者進行處理。

3)LifecycleBase

Lifecycle接口的默認實現,實現init、start、stop、destroy等方法。對觀察者的增加、查找和刪除等操作會適配器方式,由組合的LifecycleSupport實例來完成。

4)LifecycleSupport

觀察者的實際管理類,實現觀察者的註冊、刪除、查詢、調用等操作。

5)LifecycleListener

生命週期的觀察者,定義了觀察者的事件處理接口lifecycleEvent(LifecycleEvent event)。

6)ServerLifecycleListener

實際的觀察者,實現了事件處理接口。

7)LifecycleEvent

觀察者使用的參數,它封裝了事件來源、事件類型和事件數據,使得觀察者可以按事件來源和事件類型分類處理事件。

三、生命週期重要過程

1. 觀察者註冊

觀察者的註冊可以通過xml方式配置,也可以通過直接調用Lifecycle的觀察者添加方法。server.xml中觀察者配置如下:

<Server port="8005" shutdown="SHUTDOWN">  
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />  
  <Listener className="org.apache.catalina.core.JasperListener" />  
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />  
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />  
...  
</Server>  
LifecycleSupport的觀察者註冊代碼如下:

public final class LifecycleSupport {  
    // 觀察者數組  
    private LifecycleListener listeners[] = new LifecycleListener[0];  
    ...  
    public void addLifecycleListener(LifecycleListener listener) {  
  
      synchronized (listenersLock) {  
          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;  
      }  
  
    }  
}  
觀察者是通過數組來維護,每次增加一個新的觀察者,都需要將當前數組長度加1,將原來數組內容拷貝到新的數組中。對這裏的設計我比較困惑,爲什麼採用這種數組擴容方式,這樣每次增加新增觀察者都需要數組拷貝,影響性能。可能的一個原因是,考慮到觀察者數目少和新增的次數少,這種方式可以減少內存佔用。

2. 通知觀察者 
組件的生命週期中狀態發生改變時,都會發出事件,通知觀察者處理。下面以LifecycleBase中init()方法舉例說明。 

public abstract class LifecycleBase implements Lifecycle {  
    private LifecycleSupport lifecycle = new LifecycleSupport(this);  
    // 當前狀態  
    private volatile LifecycleState state = LifecycleState.NEW;  
    public synchronized final void init() throws LifecycleException {  
        if (!state.equals(LifecycleState.NEW)) {  
            invalidTransition(Lifecycle.BEFORE_INIT_EVENT);  
        }  
        // 狀態轉移到INITIALIZING,會發送事件  
        setState(LifecycleState.INITIALIZING);  
        initInternal();  
        setState(LifecycleState.INITIALIZED);  
    }  
  
    protected synchronized void setState(LifecycleState state, Object data) {  
        ...  
        this.state = state;  
        // state爲枚舉類型,獲取該枚舉值對應的事件類型  
        String lifecycleEvent = state.getLifecycleEvent();  
        if (lifecycleEvent != null) {  
            // 發起事件通知  
            fireLifecycleEvent(lifecycleEvent, data);  
        }  
    }  
  
    // 調用LifecycleSupport進行事件處理  
    protected void fireLifecycleEvent(String type, Object data) {  
        lifecycle.fireLifecycleEvent(type, data);  
    }  
}  
LifecycleSupport中的事件處理方法如下: 

public void fireLifecycleEvent(String type, Object data) {  
    // 包裝事件類型和數據  
    LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);  
    // 循環,通知所有觀察者進行事件處理  
    LifecycleListener interested[] = listeners;  
    for (int i = 0; i < interested.length; i++)  
        interested[i].lifecycleEvent(event);  
  
}  
3. 觀察者事件處理 
以ServerLifecycleListener爲例,說明觀察者事件處理過程。

public class ServerLifecycleListener 
    implements ContainerListener, LifecycleListener, PropertyChangeListener { 
    ... 
    public void lifecycleEvent(LifecycleEvent event) { 
        Lifecycle lifecycle = event.getLifecycle(); 
        if (Lifecycle.START_EVENT.equals(event.getType())) { 
                if (lifecycle instanceof Server) { 
                    ... 
                } 
                if( lifecycle instanceof Service ) { 
                   ... 
                }           
                if (lifecycle instanceof StandardContext){ 
                    ... 
                } 
            
        } else if (Lifecycle.AFTER_STOP_EVENT.equals(event.getType())) { 
                ... 
        } 
    } 
} 
觀察者可以通過事件來源(lifecycle)和事件類型(eventType)對事件分類處理。 
四、 總結 
tomcat中事件處理機制比較靈活,在日常工作的設計中值得借鑑,比如下面的業務場景:對客戶投訴的創建、撤銷、終止等,可以採用如下處理方式: 
--生命週期管理-- 
1. 創建統一的投訴業務生命週期Lifecycle,如create、cancel、destroy等。 
2. 定義投訴業務的狀態枚舉類(對應tomcat中LifecycleState),枚舉類中定義每個狀態對應的事件類型。 
--觀察者註冊-- 
3. 創建觀察者管理service(對應tomcat中的LifecycleSupport)。觀察者列表可以通過spring bean方式注入。 
--觀察者通知-- 
4. 在生命週期中狀態改變時,比如投訴創建時,發送事件通知,調用觀察者管理service,通知觀察者處理。 
5. 包裝觀察者所需要的數據(對應tomcat中的LifecycleEvent),如事件來源、類型等,供觀察者使用。 
--觀察者處理-- 
6. 定義實際觀察者,按事件來源和類型分別做業務處理,比如投訴創建時,將投訴發生時用戶的業務開通快照記錄下來。 

轉載至:http://learnworld.iteye.com/blog/1013751

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章