Tomcat架構(gòu)及其重要組件

- Server是管理Service接口的,是Tomcat的一個(gè)頂級容器。管理著多個(gè)Service
- Service 是服務(wù),管理這一個(gè)Container和多個(gè)Connector,Service的存在依賴于Server
- Container : 一個(gè)或者多個(gè)Container 可以對應(yīng)一個(gè)Connector,這樣就組成了一個(gè)Service,Service生命周期的由Server進(jìn)行管理。
- Container和Connector之間的交互媒介是Service,一個(gè)Service可以對應(yīng)多個(gè)Connector,但是只能有一個(gè)Container容器
Server
- Server 管理著所有的Service。它的主要作用是提供一個(gè)接口可以讓其它程序能夠訪問這個(gè)Service集合,同時(shí)維護(hù)所有service的生命周期等。
Server在Tomcat中的標(biāo)準(zhǔn)實(shí)現(xiàn)是StandardServer。看一下其內(nèi)部的addServiec方法
@Override
//FIXME: 它是怎樣調(diào)用起來Service 方法的哪?
public void addService(Service service) {
service.setServer(this);
//同步
synchronized (servicesLock) {
Service results[] = new Service[services.length + 1];
System.arraycopy(services, 0, results, 0, services.length);
results[services.length] = service;
services = results;
if (getState().isAvailable()) {
try {
service.start();
} catch (LifecycleException e) {
// Ignore
}
}
// Report this property change to interested listeners
support.firePropertyChange("service", null, service);
}
}
可以看到,在添加Service到Server的時(shí)候,它是將原有數(shù)組的長度加一并將數(shù)組添加到最后。然后啟動(dòng)最新添加的Service
Service
Service 在Tomcat中的標(biāo)準(zhǔn)實(shí)現(xiàn)是StandardService,Service 可以說是一個(gè)標(biāo)準(zhǔn)的服務(wù),擁有獨(dú)立的端口號。
在Service 中可以含有多個(gè)Connector和唯一的一個(gè)Container.這樣的設(shè)計(jì)模式可以允許 例如SSL加密過的請求和沒有經(jīng)過SSL加密的請求在一個(gè)APP中同時(shí)存在
Service 中的setContainer()
@Override
public void setContainer(Engine engine) {
Engine oldEngine = this.engine;
if (oldEngine != null) {
// 移除原有Container
oldEngine.setService(null);
}
this.engine = engine;
if (this.engine != null) {
this.engine.setService(this);
}
if (getState().isAvailable()) {
if (this.engine != null) {
try {
//開啟Engin
this.engine.start();
} catch (LifecycleException e) {
log.warn(sm.getString("standardService.engine.startFailed"), e);
}
}
// Restart MapperListener to pick up new engine.
try {
mapperListener.stop();
} catch (LifecycleException e) {
log.warn(sm.getString("standardService.mapperListener.stopFailed"), e);
}
try {
mapperListener.start();
} catch (LifecycleException e) {
log.warn(sm.getString("standardService.mapperListener.startFailed"), e);
}
if (oldEngine != null) {
try {
oldEngine.stop();
} catch (LifecycleException e) {
log.warn(sm.getString("standardService.engine.stopFailed"), e);
}
}
}
// Report this property change to interested listeners
support.firePropertyChange("container", oldEngine, this.engine);
}
Service 的setContainer方法設(shè)置Engine容器,然后啟動(dòng)這個(gè)容器,并將原有的容器的停止掉。Service 的setConnector幾乎是同樣的套路
Container
Container 由四個(gè)子容器組成:
- Engine : 表示整個(gè)Catalina Servlet引擎,是Container 只用最高層,用來管理Host 或者Context的實(shí)現(xiàn)
- 如果你想攔截每一個(gè)到Servlet的請求,可以通過
- Host :表示一個(gè)Engine管理下的一個(gè)虛擬主機(jī),比如你訪問的Localhost就是一個(gè)虛擬主機(jī)。作用是運(yùn)行多個(gè)應(yīng)用
其處理過程可以總結(jié)如下:- 為特定的請求URL選擇一個(gè)Context容器
- 把Context容器綁定到線程中
- 判斷是否是一個(gè)異步請求
- 讓Context去處理這個(gè)請求
- Context執(zhí)行invoke方法,進(jìn)入管道中,由StandardContextValve(是ContextValve的標(biāo)準(zhǔn)實(shí)現(xiàn)類)處理
- Context:Context 是用來管理Servlet的容器,Context就對應(yīng)一個(gè)應(yīng)用。所以我們部署應(yīng)用時(shí)需要?jiǎng)?chuàng)建一個(gè)Context容器,Context負(fù)責(zé)管理Wrapper.
- Wrapper : 用來管理一個(gè)Servlet的生命周期
Connector
Connector 是Tomcat的連接器,主要任務(wù)是負(fù)責(zé)處理瀏覽器發(fā)送過來的請求,并創(chuàng)建一個(gè)Request和Response對象,用于和前端Client交換數(shù)據(jù),然后產(chǎn)生一個(gè)線程,并將Request對象和Response對象傳遞給線程,后面對這兩個(gè)線程的處理就是Container的事情了
- 實(shí)例化Connector,構(gòu)造一個(gè)Connector對象
- 調(diào)用Connector的initIntenal方法,初始化Connetor
- 調(diào)用ProtocolHanlder的init方法,完成ProtocolHanlder的初始化。這個(gè)過程包括了創(chuàng)建線程池并創(chuàng)建一個(gè)線程處理瀏覽器請求
- 調(diào)用Connector的startIntenal方法,啟動(dòng)Connector
- 調(diào)用ProtocolHandler的start方法,啟動(dòng)Protocolhanlder
- 調(diào)用MapperListener的start方法,啟動(dòng)監(jiān)聽器程序
不同于Container ,Connector是一個(gè)實(shí)現(xiàn)類.其相當(dāng)于一個(gè)容器處理基于Http的請求
。CoyoteAdapter,是connector和container的橋梁,經(jīng)過這一步,請求就從connector傳遞到container中里了。Adapter
要注意的是:最先處理請求的Request是org.apache.coyote.Request類型,這是一個(gè)Tomcat中一個(gè)輕量級對象,完成基本的請求處理后很容易被JVM回收,那為什么不直接交給Connector.Request對象處理呢?由于后者是Servlet容器真正傳遞的對象其完成的職責(zé)比前者復(fù)雜,這里使用org.apache.coyote.Request主要減輕后者的任務(wù)負(fù)擔(dān),出于性能考慮才這么設(shè)計(jì)。
從connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);這句代碼中可以知道下一步的處理需要交給Container容器了。
Context容器和Wrapper
Wrapper 接口是Context的抽象接口
Context的啟動(dòng):
Context的啟動(dòng)過程就是加載整個(gè)類資源文件和打開子容器,以及pipeline的過程。
StandardContextValve的invoke 方法會(huì)通過request得到相應(yīng)的ContextWrapper,在這個(gè)過程中如果沒有發(fā)生異常,服務(wù)端會(huì)向client 發(fā)送一個(gè)ack響應(yīng)
StandardContext的處理流程可以用下面的圖來簡化:

- StandardContext的addServlet會(huì)添加一個(gè)Servlet類,并通過Servlet名字分配一個(gè)ServletWrppar,如果沒有則為其新建一個(gè)。通過這個(gè)Wrappar來管理這個(gè)Servlet。。
- Wrapper與Servlet息息相關(guān),其中的loadServlet負(fù)責(zé)裝載Servlet.Wrapper是最底層
- Standard類主要負(fù)責(zé)初始化一個(gè)Servlet實(shí)例,并調(diào)用該實(shí)例的init方法,然后通知感興趣的事件監(jiān)聽程序。用了Wrapper的invoke方法,這個(gè)方法完成什么呢?
附錄: 一個(gè)HTTP請求是怎樣通過Tomcat到你的應(yīng)用中的
Http請求在Container中的傳遞流程