你可能不那麼知道的Tomcat生命週期管理 | 博學谷狂野架構師

語言: CN / TW / HK

Tomcat生命週期管理

img

各種元件如何統一管理

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方法
COPY@Override
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方法
COPY@Override
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方法
COPY@Override
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方法
COPY@Override
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方法,通過相應的模板方法【模板設計模式】,提供元件的統一生命週期的管理、事件排程。

本文由傳智教育博學谷狂野架構師教研團隊釋出。

如果本文對您有幫助,歡迎關注點贊;如果您有任何建議也可留言評論私信,您的支援是我堅持創作的動力。

轉載請註明出處!