tomcat + spring mvc原理(二):tomcat容器初始化加載和啓動


    tomcat + spring mvc 原理(一):tomcat原理綜述比較詳細的敘述了tomcat容器的靜態結構和容器的配置,從tomcat動態運行來講,我也在原理(一)中簡單論述了:

顯然,這種運作模式要求:tomcat需要有監視指定目錄,一旦有新的war包加入,就完成解包並動態加載編譯後的class的能力;tomcat需要有網絡端口開閉和監視的機制,維護線程池來處理隨時可能到來的請求;tomcat還需要將到來的請求順利地傳遞給spring mvc服務,然後再將服務返回的數據發送出去。

    其實,對tomcat的理解,不只是應該瞭解靜態容器結構,對於動態運行方面,應該包括:    

  1. 容器的初始加載和啓動
  2. war包動態監視和加載
  3. 網絡請求的監控和處理

    這樣基本就涵蓋了tomcat所有的基本運作原理。本文主要涉及第一部分:容器的初始加載與啓動。

容器通用生命週期標準

    tomcat的容器,包括Server、Service、Connector、Engine、Host、Context、Wrapper都繼承自同一個管理生命週期的接口:Lifecycle。
    首先,這個接口類定義了這些容器的初始化、啓動、停止和銷燬的標準生命週期方法。

public interface Lifecycle {
    ......
    //容器初始化
    public void init() throws LifecycleException;

    //容器啓動
    public void start() throws LifecycleException;

    //容器停止
    public void stop() throws LifecycleException;

    //容器銷燬
    public void destroy() throws LifecycleException;

    ......
}

    其次,這個接口類定義了這些容器所處生命週期的狀態事件名和狀態事件監聽器的管理。

public 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";


    /**
     *兩個獲取生命週期狀態的方法
     **/
     //獲取狀態,內含事件和狀態名
    public LifecycleState getState();
    //獲取狀態名
    public String getStateName();


    /**
     *狀態事件監聽器。LifecycleListener中包含一個處理事件的方
     *法LifecycleEvent()
     **/
     //添加狀態事件監聽器
    public void addLifecycleListener(LifecycleListener listener);

     //獲取所有狀態事件監聽器
    public LifecycleListener[] findLifecycleListeners();

    //移除狀態事件監聽器
    public void removeLifecycleListener(LifecycleListener listener);

    ......
}

容器通用生命週期的實現

    Lifecycle接口類的通用實現是在LifecycleBase類中。
    容器都繼承自LifeCycleBase類,LifecycleBase類爲容器提供了基本生命週期方法的一般實現和生命週期狀態監聽器的管理實現。

  • 生命週期狀態監聽器的管理實現

    這一部分主要是監聽器管理的實現,但真正發揮作用是在生命週期方法的實現中。
    LifecycleBase中使用一個自己定義的List–CopyOnWriteArrayList來存儲LifecycleListener,本質上還是一個List,具體實現過於細節,這裏不做研究。同時LifecycleBase基於監聽器的List,對添加監聽器、移除監聽器、獲取所有監聽器的方法實現了邏輯。

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);
}

需要特別注意的是,LifecycleBase實現了生命週期狀態事件監聽器處理事件的方法,其實就是遍歷了監聽器List,使用監聽器的lifecleEvent方法處理了事件。這一方法在後面實現的init(),start()等生命週期的方法中都有間接調用,相當於只要更改了容器所處生命週期的狀態,就需要對發佈這一事件,調用該容器的關注該事件的監聽器處理事件。

protected void fireLifecycleEvent(String type, Object data) {
    LifecycleEvent event = new LifecycleEvent(this, type, data);
    for (LifecycleListener listener : lifecycleListeners) {
        listener.lifecycleEvent(event);
    }
}
  • 生命週期方法實現

    LifecycleBase實現了Lifecycle的標準生命週期方法init()、start()、stop()、destroy()的邏輯。下面主要以init()和start()爲例介紹實現的基本特點。

//init()生命週期方法實現
@Override
public final synchronized void init() throws LifecycleException {
    if (!state.equals(LifecycleState.NEW)) {
    //new狀態是最初加載時必須爲NEW
        invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
    }

    try {
        setStateInternal(LifecycleState.INITIALIZING, null, false);

        initInternal();        //實際生命週期實現邏輯,由子類實現

        setStateInternal(LifecycleState.INITIALIZED, null, false);
    } catch (Throwable t) {
        handleSubClassException(t, "lifecycleBase.initFail", toString());
    }
}

通過init()的具體代碼可以發現,LifecycleBase中主要就是設置了生命週期的狀態,其中setStateInternal()除了設置了狀態、校驗了狀態是否正確之外,還調用了上文提到的fireLifecycleEvent()響應了當前狀態事件,觸發了監聽該事件的監聽器監聽到該事件的邏輯。由於不同子類(主要是不同容器)在初始化時所需要做的事不一樣,所以initInternal()是真正被子類重載後做初始化的事情的方法。
    start()內部邏輯的特點和init()很相似,也是做了設置生命週期的狀態,稍微複雜一些是需要:1.判斷狀態是否處於可以start()的階段,不然就需要先init();2.是否失敗需要stop()。

@Override
public final synchronized void start() throws LifecycleException {
    //校驗狀態,是否已經啓動
    if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
            LifecycleState.STARTED.equals(state)) {

        if (log.isDebugEnabled()) {
            Exception e = new LifecycleException();
            log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
        } else if (log.isInfoEnabled()) {
            log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
        }

        return;  //已經啓動,直接返回
    }

    if (state.equals(LifecycleState.NEW)) {
        init();  //如果未初始化,先初始化化
    } else if (state.equals(LifecycleState.FAILED)) {
        stop();  //失敗直接終止
    } else if (!state.equals(LifecycleState.INITIALIZED) &&
            !state.equals(LifecycleState.STOPPED)) {
        invalidTransition(Lifecycle.BEFORE_START_EVENT);
    }

    try {
        setStateInternal(LifecycleState.STARTING_PREP, null, false);

        startInternal(); //實際生命週期實現邏輯,由子類實現

        if (state.equals(LifecycleState.FAILED)) {
            stop(); //失敗直接終止
        } else if (!state.equals(LifecycleState.STARTING)) {
            invalidTransition(Lifecycle.AFTER_START_EVENT);
        } else {
            setStateInternal(LifecycleState.STARTED, null, false);
        }
    } catch (Throwable t) {
        handleSubClassException(t, "lifecycleBase.startFail", toString());
    }
}

可以看到,依舊有很多狀態變更,和處理狀態變更、發佈狀態變更事件的setStateInternal()的調用。

宏觀來看各種容器生命週期的實際流程

    在原理(一)我已經詳細介紹了各種容器的配置、靜態嵌套結構和各自的功能,鋪墊了這麼多,終於可以介紹各種容器是如果加載初始化的了。
在這裏插入圖片描述
    首先按照基本嵌套結構,如圖,最開始需要先啓動Server,不管是Tomcat獨立部署包還是spring mvc中的嵌入式tomcat-embed包,都需要先調用Server.init(),然後調用Server.start()。實際上,tomcat中Server的標準實現是StandardServer,根據LifecycleBase中實現的init()和start()的代碼,實際上會調用子類重載的initInternal()和startInternal()方法。在StandardServer的initInternal()和startInternal()方法中,會調用StandardServer類中的Service實例的init()和start()方法…另一個方面,在StandardServer的addService()方法也會調用添加的Service實例(實際是StandardService類)的start()方法。同樣的邏輯適用於Service下的Engine容器。
    Engine以下的Host、Context、Wrapper略有不同,因爲它們都實現自Container接口,繼承了Container接口的標準實現ContainerBase。Container中將每一種容器的包含關係定義爲父子關係,即Host是Engine類的Container child,使用這個Container[]來存儲所有Host子容器。同理Host和Context、Context和Wrapper都是相同的關係。在ContainerBase中實現的startInternal()有:

Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (int i = 0; i < children.length; i++) {
    results.add(startStopExecutor.submit(new StartChild(children[i])));
}

    需要特別注意的是,Container啓動子容器的時候不一定是通過init()或者start()中調用相應子容器的生命週期函數。在容器的addChild方法中,也會調用子容器的start()方法,初始化加載和啓動子容器,比如host的addChild(context)方法會調用context的start方法。
統一使用多線程執行調用child的start方法,這樣各個容器都能按順序初始化和啓動。
    關於邊界的情況,比如Wrapper部分,由於和spring mvc相關,會在spring mvc原理裏面敘述。

本系列文章:
tomcat + spring mvc原理(一):tomcat原理綜述和靜態架構
tomcat + spring mvc原理(三):tomcat網絡請求的監控與處理1
tomcat + spring mvc原理(四):tomcat網絡請求的監控與處理2
tomcat + spring mvc原理(五):tomcat Filter組件實現原理
tomcat + spring mvc原理(六):tomcat WAR包的部署與加載

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