最近在學習tomcat源碼,算是把tomcat的整個流程梳理通了。
從上圖來看,tomcat把模塊化使用到了極致,配合組件生命周期的管理,讓代碼看起來結構清晰,而且很容易進行業務擴展。
1.上圖的接口Sever,Service,Connector,Container…..都是一個組件接口,這些組件的關系是,Server包含一個或多個Service,一個Service包含多個Container和與這個Container相關聯的Connector,然后Container根據自身需要關聯下面的Jasper,Naming…..等組件。Tomcat提供一鍵式啟動和關閉服務,就是以剛剛所說的組件之間的關系來執行的,在啟動一個組件的時候,會啟動與其相關聯的組件,這樣會啟動所有的組件,而客戶端不需要關心其余組件的啟動細節。
拿StandardServer的啟動來舉例:
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
//這個方法負責啟動前的准備工作,用觀察者模式實現
setState(LifecycleState.STARTING);
//標記組件的狀態
globalNamingResources.start();
//相關聯組件的啟動
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}
說明一下,組件的啟動和關閉時,調用組件的start和stop方法,這兩個是模板方法,模板方法中調用的startInternal方法由子類來實現。可以看到Sever會啟動globalNamingResource組件和關聯的Service組件,實現一鍵式功能。
2. startInternal方法的第一行
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
是為了做一些Sever啟動前的准備工作,使用的是觀察者模式來實現的。
Tomcat的觀察者模式主要接口有:Lifecycle,LifecycleEvent,LifecycleListener,LifecycleSupport。
其中LifecycleListener是觀察者,負責等待通知然后進行一些與發送的事件想匹配的操作,具體實現類有ContextConfig, HostConfig, EngineConfig,LifecycleEvent 是發送的事件,Lifecycle是被觀察者(主題),具體的實現類有StandardServer,StandardContext等等組件,組件啟動的時候,會將啟動的動作封裝成一個事件,然后調用觀察者的回調方法,來進行相關操作,LifecycleSupport是一個生命周期的管理類,組件的觀察者的管理委托LifecycleSupport來實現,因此所有的組件中都有一個LifecycleSupport的引用,在容器類的抽象類ContainerBase中代碼如下:
protected LifecycleSupport lifecycle = new LifecycleSupport(this);
public void addLifecycleListener(LifecycleListener listener) {
lifecycle.addLifecycleListener(listener);
}
public LifecycleListener[] findLifecycleListeners() {
return lifecycle.findLifecycleListeners();
public void removeLifecycleListener(LifecycleListener listener) {
lifecycle.removeLifecycleListener(listener);
}
對觀察者的管理以及動作的觸發,都委托LifecycleSupport來實現。
這里主要做三件事:調用組件的啟動方法,啟動組件;調用子容器的啟動方法,啟動子容器;通知容器的觀察者,使其執行相應的啟動動作。每一層次的容器都這樣啟動,最終整個Tomcat啟動完畢。
3. Tomcat中有四種不同的容器:
Engine:代表整個Catalina servle引擎
Host:代表虛擬主機
Context:代表某個web應用
Wrapper:代表某個應用中的servlet
這些容器都是父子的關系,Engine位於最頂層,一個Engine包含多個Host,一個Host(虛擬主機)包含多個Context(web應用),一個Context(web 應用)包含多個Wrapper(servlet),Wrapper位於最底層,沒有孩子。當父容器啟動時,相應的子容器也應該啟動,子容器的子容器也啟動。
4.好了,先說到這兒,還有一部分容器管道沒有說,下次再介紹一下tomcat如何用管道閥來簡化開發流程和增強程序擴展性。