最近在閱讀“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. 定義實際觀察者,按事件來源和類型分別做業務處理,比如投訴創建時,將投訴發生時用戶的業務開通快照記錄下來。