How Tomcat works — 四、tomcat啟動(3),tomcatworks
上一節說到StandardService負責啟動其子組件:container和connector,不過注意,是有先後順序的,先啟動container,再啟動connector,這一節先來看看container。
目錄
- Pipeline和Vavle
- StandardEngine類和StandardHost類
- StandardContext類
- 總結
Pipeline和Vavle
在第二節(How Tomcat works — 二、tomcat啟動(1))中沒有介紹關於Pipeline和Vavle,因為前面側重的是整個架構,但是在初始化的時候就不得不說了。
Pipeline,就是一根管道,用來連接兩個容器,在一個容器流向下一個容器的時候使用。在tomcat中也是這個意思,很形象,Engine、Host等都是容器,在執行完上一個容器(比如Engine)的相關操作的時候要開始執行下一個容器(比如Host)的操作了,這個時候需要經過一根管道pipeline,那麼我們可以在管道中執行一個其他必要的操作,這個時候可以在管道上面添加Vavle(閥),一根管道pipeline上可以有多個閥門(也很形象)。每根管道都有一個默認的閥門。
在tomcat實現中有一個實現了Pipeline接口的類StandardPipeline——是每兩個容器之間的管道,每個容器都有一個默認的Valve實現StandardEnginevavle、StandardHostValve、StandardContextVavle、StandardWrapperVavle。
其實valve的作用和filter的作用類似。
StandardEngine類
StandardEngine作為整個容器的最頂層負責啟動其子組件——StandardHost,對,他就這一個作用。
StandardEngine.initInternal
這個方法被超類LifecycleBase.init方法調用,主要作用就是調用超類LifecycleMBeanBase.initInternal方法注冊MBean,並初始化一個startStopExecutor(ThreadPoolExecutor),後面用來使用線程啟動子容器。
StandardEngine.startInternal
這個方法的主要作用就是調用父類的方法Container.startInternal——主要的操作就在這個方法裡面:

![]()
protected synchronized void startInternal() throws LifecycleException {
// Start our subordinate components, if any
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
logger = null;
getLogger();
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
Realm realm = getRealmInternal();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
// Start our child containers, if any
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<Future<Void>>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
boolean fail = false;
for (Future<Void> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
fail = true;
}
}
if (fail) {
throw new LifecycleException(
sm.getString("containerBase.threadedStartFailed"));
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
setState(LifecycleState.STARTING);
// Start our thread
threadStart();
}
View Code
- manager、cluster、realm、resource如果有的話全部啟動(所以其實tomcat本身就是支持集群的)
- 調用findChildren方法找到左右子容器——也就是所有的StandardHost(默認只有一個)
- 對於每個子容器(StandardHost)使用線程啟動,StartChild類實現了Callable接口,在call方法裡面執行傳入容器的start方法,將子容器啟動作為一個task,然後使用ThreadPoolExecutor.submit提交task
- 然後等待這些Future執行完(因為裡面是各個子容器的初始化和啟動工作,後面connector必須在容器准備好之後才能啟動)
- 啟動pipeline(這裡就是StandardPipeline),pipeline會啟動所包含的所有vavle(這裡就是只有StandardEngineValve)
- setState會通知所有監聽了StandardEngine事件的listener
- threadStart,啟動一個後台線程執行包含的所有閥門的backgroundProcess方法,並觸發Lifecycle.PERIODIC_EVENT事件
StandardHost類
StandardHost的作用和StandardEngine類似,都是初始化啟動子容器,不過這裡是StandardContext。啟動的方式也一樣,所以就不再詳述。
StandardContext類
這個類才是重中之重,解析web.xml、部署webapp都在這兒實現。在StandardHost中調用StandardContext.start方法,執行的是超類LifecycleBase.start方法,主要進行了如下操作
- 調用init方法初始化StandardContext
- 調用startInternal方法啟動StandardContext
init

在該方法中主要進行了MBean的注冊,再就是觸發了Lifecycle.AFTER_INITEVENT事件,ContextConfig是StandardContext的listener,在發生該事件的時候執行ContextConfig.init方法,在該方法中主要是構造一個能解析web.xml的digester。
startInternal
由於LifecycleBase沒有實現該方法,所以就是直接調用StandardContext.startInternal,在StandardContext.startInternal方法中主要進行了如下操作:
- setResource:添加新的resource
- 如果webappLoader為null則初始化
- 初始化charset mapper
- 設置webapp工作目錄,比如%TOMCAT_HOME%/work//Catalina/localhost/_等
- 觸發Lifecycle.CONFIGURE_START_EVENT事件,ContextConfig監聽了該事件,會進行解析web.xml
- 啟動所有的children(StandardWrapper,代表所有配置的servlet)
- 初始化Standardmanager
- 配置initParam
- 配置啟動filter、listener

總結
container部分終於啟動完成了,不過還是有些部分略過了,比如StandardWrapper(這個還可以往深挖,不過也包含在StandardContext的啟動過程中)初始化和webapp的發布。到現在發現,這些啟動過程就是圍繞生命周期的這幾個方法展開:
- start和init:LifecycleBase提供了默認實現
- startInternal和initInternal:這兩個方法每個類都是重載實現自己需要啟動的東西