你可能不那麼知道的Tomcat生命週期管理 | 博學谷狂野架構師
Tomcat生命週期管理
各種元件如何統一管理
Tomcat的架構設計是清晰的、模組化、它擁有很多元件,加入在啟動Tomcat時一個一個元件啟動,很容易遺漏元件,同時還會對後面的動態元件拓展帶來麻煩。如果採用我們傳統的方式的話,元件在啟動過程中如果發生異常,會很難管理,比如你的下一個元件呼叫了start方法,但是如果它的上級元件還沒有start甚至還沒有init的話,Tomcat的啟動會非常難管理,因此,Tomcat的設計者提出一個解決方案:用Lifecycle管理啟動,停止、關閉。
生命週期統一介面
Tomcat內部架構中各個核心元件有包含與被包含關係,例如:Server包含了Service.Service又包含了Container和Connector,這個結構有一點像資料結構中的樹,樹的根結點沒有父節點,其他節點有且僅有一個父節點,每一個父節點有0至多個子節點。所以,我們可以通過父容器啟動它的子容器,這樣只要啟動根容器,就可以把其他所有的容器都啟動,從而達到了統一的啟動,停止、關閉的效果。
所有所有元件有一個統一的介面——Lifecycle,把所有的啟動、停止、關閉、生命週期相關的方法都組織到一起,就可以很方便管理Tomcat各個容器元件的生命週期。
Lifecycle其實就是定義了一些狀態常量和幾個方法,主要方法是init,start,stop三個方法。
例如:Tomcat的Server元件的init負責遍歷呼叫其包含所有的Service元件的init方法。
注意:Server只是一個介面,實現類為StandardServer,有意思的是,StandardServer沒有init方法,init方法是在哪裡,其實是在它的父類LifecycleBase中,這個類就是統一的生命週期管理。
COPYpublic class StandardService extends LifecycleMBeanBase implements Service
public abstract class LifecycleMBeanBase extends LifecycleBase
implements JmxEnabled
LifecycleBase
COPYpublic abstract class LifecycleBase implements Lifecycle {
@Override
public final synchronized void init() throws LifecycleException {
//這個就是為了防止 元件啟動的順序不對
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
//只打印核心元件
if(this.getClass().getName().startsWith("org.apache.catalina.core")||this.getClass().getName().startsWith("org.apache.catalina.connector")){
System.out.println(this.getClass()+"--init()");
}
setStateInternal(LifecycleState.INITIALIZING, null, false);
//呼叫子類的initInternal方法
initInternal();
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.initFail", toString());
}
}
}
所以StandardServer最終只會呼叫到initInternal方法,這個方法會初始化子容器Service的init方法
為什麼LifecycleBase這麼玩,其實很多架構原始碼都是這麼玩的,包括JDK的容器原始碼都是這麼玩的,一個類,有一個介面,同時抽象一個抽象骨架類,把通用的實現放在抽象骨架類中,這樣設計就方便元件的管理,使用LifecycleBase骨架抽象類,在抽象方法中就可以進行統一的處理。
LifeCycle原始碼分析
作用
元件生命週期方法的通用介面。 Catalina元件可以實現此介面(以及它們支援的功能的適當介面),以便提供一致的機制來啟動和停止元件
狀態圖
Tomcat中的事件觸發是通過這些狀態來判定的。
COPY* start()
* -----------------------------
* | |
* | init() |
* NEW -»-- INITIALIZING |
* | | | | ------------------«-----------------------
* | | |auto | | |
* | | \|/ start() \|/ \|/ auto auto stop() |
* | | INITIALIZED --»-- STARTING_PREP --»- STARTING --»- STARTED --»--- |
* | | | | |
* | |destroy()| | |
* | --»-----«-- ------------------------«-------------------------------- ^
* | | | |
* | | \|/ auto auto start() |
* | | STOPPING_PREP ----»---- STOPPING ------»----- STOPPED -----»-----
* | \|/ ^ | ^
* | | stop() | | |
* | | -------------------------- | |
* | | | | |
* | | | destroy() destroy() | |
* | | FAILED ----»------ DESTROYING ---«----------------- |
* | | ^ | |
* | | destroy() | |auto |
* | --------»----------------- \|/ |
* | DESTROYED |
* | |
* | stop() |
* ----»-----------------------------»------------------------------
介面定義
Lifecycle介面統一管理Tomcat生命週期。一共做了4件事:
- 定義13個string型別常量,用於LifecycleEvent時間的type屬性中,用於區分元件發出的LifecycleEvent事件時的狀態。
- 定義三個管理監聽器的方法,addLifecycleListener、findLifecycleListeners、removeLifecycleListener。
- 定義4個生命週期的方法,init、start、stop、destory,用於執行生命週期的各個階段的操作。
- 定義了獲取當前狀態的兩個方法,getState、getStateName、用於獲取當前的狀態。
COPYpublic interface Lifecycle {
// 13個狀態常量值
public static final String BEFORE_INIT_EVENT = "before_init";
public static final String AFTER_INIT_EVENT = "after_init";
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 static final String AFTER_DESTROY_EVENT = "after_destroy";
public static final String BEFORE_DESTROY_EVENT = "before_destroy";
public static final String PERIODIC_EVENT = "periodic";
public static final String CONFIGURE_START_EVENT = "configure_start";
public static final String CONFIGURE_STOP_EVENT = "configure_stop";
// 3個監聽器方法
public void addLifecycleListener(LifecycleListener listener);
public LifecycleListener[] findLifecycleListeners();
public void removeLifecycleListener(LifecycleListener listener);
// 4個生命週期方法
public void init() throws LifecycleException;
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
public void destroy() throws LifecycleException;
// 2個當前狀態方法
public LifecycleState getState();
public String getStateName();
}
預設實現類
COPYpublic abstract class LifecycleBase implements Lifecycle {
// 源元件的當前狀態,不同狀態觸發不同事件
private volatile LifecycleState state = LifecycleState.NEW;
}
監聽器相關方法
事件監聽器需要三個參與者:
- 事件物件:用於封裝事件的資訊,在事件監聽器介面的同一方法中作為引數使用,繼承自java.util.EventObject類。
- 事件源:觸發事件的源頭,不同事件源觸發不同事件型別。
- 事件監聽器:負責監聽事件源發出的事件。實現 java.util.EventListener 介面。
COPY// 用於事件通知的已註冊LifecycleListener列表
private final List<LifecycleListener> lifecycleListeners =
new CopyOnWriteArrayList<>();
@Override
public void addLifecycleListener(LifecycleListener listener) {
lifecycleListeners.add(listener);
}
@Override
public LifecycleListener[] findLifecycleListeners() {
return lifecycleListeners.toArray(new LifecycleListener[0]);
}
@Override
public void removeLifecycleListener(LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
// 子類根據當前狀態觸發不同事件,實現不同操作
protected void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(this, type, data);
for (LifecycleListener listener : lifecycleListeners) {
listener.lifecycleEvent(event);
}
}
生命週期方法
LifecycleBase 類是Lifecycle 介面的預設實現,所有實現了生命週期的元件都直接或者間接的繼承自LifecycleBase。
init方法
[email protected]
public final synchronized void init() throws LifecycleException {
// 只有 NEW 狀態可以呼叫
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
// 設定 生命週期狀態 -- INITIALIZING,觸發相應事件
setStateInternal(LifecycleState.INITIALIZING, null, false);
// 模板方法,由具體子類實現
initInternal();
// 執行完成,設定生命週期狀態 -- INITIALIZED,觸發相應事件
setStateInternal(LifecycleState.INITIALIZED, null, false);
}
Start方法
[email protected]
public final synchronized void start() throws LifecycleException {
// 此三種狀態不執行
if (LifecycleState.STARTING_PREP.equals(state) ||
LifecycleState.STARTING.equals(state) ||
LifecycleState.STARTED.equals(state)) {
return;
}
// NEW 狀態 執行 init 方法
if (state.equals(LifecycleState.NEW)) {
init();
// 啟動失敗,呼叫 stop 方法
} else if (state.equals(LifecycleState.FAILED)) {
stop();
// 其它狀態,非法操作
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
throw new LifecycleException()
}
// 設定啟動狀態為 STARTING_PREP【開始準備】
setStateInternal(LifecycleState.STARTING_PREP, null, false);
startInternal();
// 呼叫完成後判斷元件啟動狀態
if (state.equals(LifecycleState.FAILED)) {
stop();
} else if (!state.equals(LifecycleState.STARTING)) {
throw new LifecycleException();
} else {
setStateInternal(LifecycleState.STARTED, null, false);
}
}
stop方法
[email protected]
public final synchronized void stop() throws LifecycleException {
// STOPPING_PREP、STOPPING、STOPPED此三種狀態不予執行
if (LifecycleState.STOPPING_PREP.equals(state) ||
LifecycleState.STOPPING.equals(state) ||
LifecycleState.STOPPED.equals(state)) {
return;
}
// 如果狀態為 NEW、修改為 STOPPED
if (state.equals(LifecycleState.NEW)) {
state = LifecycleState.STOPPED;
return;
}
// 不為 STARTED、FAILED 2種狀態,丟擲異常
if (!state.equals(LifecycleState.STARTED) &&
!state.equals(LifecycleState.FAILED)) {
throw new LifecycleException();
}
try {
// 啟動失敗,觸發事件,否則設定生命週期狀態
if (state.equals(LifecycleState.FAILED)) {
fireLifecycleEvent(BEFORE_STOP_EVENT, null);
} else {
setStateInternal(LifecycleState.STOPPING_PREP, null, false);
}
// 呼叫模板方法
stopInternal();
if (!state.equals(LifecycleState.STOPPING) &&
!state.equals(LifecycleState.FAILED)) {
throw new LifecycleException();
}
setStateInternal(LifecycleState.STOPPED, null, false);
} catch (Throwable t) {
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException();
} finally {
if (this instanceof Lifecycle.SingleUse) {
setStateInternal(LifecycleState.STOPPED, null, false);
destroy();
}
}
}
destroy方法
[email protected]
public final synchronized void destroy() throws LifecycleException {
// 啟動失敗,先呼叫 stop 方法
if (LifecycleState.FAILED.equals(state)) {
stop();
}
// DESTROYING、DESTROYED不執行了
if (LifecycleState.DESTROYING.equals(state) ||
LifecycleState.DESTROYED.equals(state)) {
return;
}
// 非法狀態
if (!state.equals(LifecycleState.STOPPED) &&
!state.equals(LifecycleState.FAILED) &&
!state.equals(LifecycleState.NEW) &&
!state.equals(LifecycleState.INITIALIZED)) {
throw new LifecycleException();
}
try {
setStateInternal(LifecycleState.DESTROYING, null, false);
destroyInternal();
setStateInternal(LifecycleState.DESTROYED, null, false);
} catch (Throwable t) {
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException();
}
}
設定狀態方法
COPYprivate synchronized void setStateInternal(LifecycleState state,
Object data, boolean check) throws LifecycleException {
// 檢查引數
if (check) {
if (state == null) {
throw new LifecycleException();
return;
}
if (!(state == LifecycleState.FAILED ||
(this.state == LifecycleState.STARTING_PREP &&
state == LifecycleState.STARTING) ||
(this.state == LifecycleState.STOPPING_PREP &&
state == LifecycleState.STOPPING) ||
(this.state == LifecycleState.FAILED &&
state == LifecycleState.STOPPING))) {
throw new LifecycleException();
}
}
this.state = state;
String lifecycleEvent = state.getLifecycleEvent();
if (lifecycleEvent != null) {
fireLifecycleEvent(lifecycleEvent, data);
}
}
監聽機制
事件監聽器需要三個參與者:
- 事件物件—用於封裝事件的資訊,在事件監聽器介面的統一方法中作為引數,一般繼承 java.util.EventObjecct類。
- 事件源—觸發事件對的源頭,不同事件源觸發不同事件。
- 事件監聽器—負責監聽事件源發出的事件,發生事件時,事件源呼叫事件監聽器的統一方法處理。監聽器一般實現java.util.EventListener介面。
COPYpublic final class LifecycleEvent extends java.util.EventObject {
public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
super(lifecycle);
this.type = type;
this.data = data;
}
}
COPYpublic interface LifecycleListener {
public void lifecycleEvent(LifecycleEvent event);
}
COPYpublic class HostConfig implements LifecycleListener {
@Override
public void lifecycleEvent(LifecycleEvent event) {
try {
host = (Host) event.getLifecycle();
if (host instanceof StandardHost) {
setCopyXML(((StandardHost) host).isCopyXML());
setDeployXML(((StandardHost) host).isDeployXML());
setUnpackWARs(((StandardHost) host).isUnpackWARs());
setContextClass(((StandardHost) host).getContextClass());
}
} catch (ClassCastException e) {
return;
}
// Process the event that has occurred
if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
check();
} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
beforeStart();
} else if (event.getType().equals(Lifecycle.START_EVENT)) {
start();
} else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
stop();
}
}
}
COPY// LifecycleBase.startInternal
this.state = state;
String lifecycleEvent = state.getLifecycleEvent();
if (lifecycleEvent != null) {
fireLifecycleEvent(lifecycleEvent, data);
}
protected void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(this, type, data);
for (LifecycleListener listener : lifecycleListeners) {
listener.lifecycleEvent(event);
}
}
模板方法
四個模板方法,由子類具體實現
COPYprotected abstract void initInternal() throws LifecycleException;
protected abstract void startInternal() throws LifecycleException;
protected abstract void stopInternal() throws LifecycleException;
protected abstract void destroyInternal() throws LifecycleException;
總結
通過提供init、start、stop、destory方法,通過相應的模板方法【模板設計模式】,提供元件的統一生命週期的管理、事件排程。
本文由
傳智教育博學谷狂野架構師
教研團隊釋出。如果本文對您有幫助,歡迎
關注
和點贊
;如果您有任何建議也可留言評論
或私信
,您的支援是我堅持創作的動力。轉載請註明出處!
- ElasticSearch還能效能調優,漲見識、漲見識了!!!
- 【必須收藏】別再亂找TiDB 叢集部署教程了,這篇保姆級教程來幫你!!| 博學谷狂野架構師
- 【建議收藏】7000 字的TIDB保姆級簡介,你見過嗎
- Tomcat架構設計剖析 | 博學谷狂野架構師
- 你可能不那麼知道的Tomcat生命週期管理 | 博學谷狂野架構師
- 大哥,這是併發不是並行,Are You Ok?
- 為啥要重學Tomcat?| 博學谷狂野架構師
- 這是一篇純講SQL語句優化的文章!!!| 博學谷狂野架構師
- 捲起來!!!看了這篇文章我才知道MySQL事務&MVCC到底是啥?
- 為什麼99%的程式設計師都做不好SQL優化?
- 如何搞定MySQL鎖(全域性鎖、表級鎖、行級鎖)?這篇文章告訴你答案!太TMD詳細了!!!
- 【建議收藏】超詳細的Canal入門,看這篇就夠了!!!
- 從菜鳥程式設計師到高階架構師,竟然是因為這個字final
- 為什麼95%的Java程式設計師,都是用不好Synchronized?
- 99%的Java程式設計師者,都敗給這一個字!
- 8000 字,就說一個字Volatile
- 98%的程式設計師,都沒有研究過JVM重排序和順序一致性
- 來一波騷操作,Java記憶體模型
- 時隔多年,這次我終於把動態代理的原始碼翻了個地兒朝天
- 再有人問你分散式事務,把這篇文章砸過去給他