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

- Server是管理Service接口的,是Tomcat的一個頂級容器要尔。管理著多個Service
- Service 是服務(wù),管理這一個Container和多個Connector低矮,Service的存在依賴于Server
- Container : 一個或者多個Container 可以對應(yīng)一個Connector,這樣就組成了一個Service遵馆,Service生命周期的由Server進行管理妒蔚。
- Container和Connector之間的交互媒介是Service,一個Service可以對應(yīng)多個Connector邪驮,但是只能有一個Container容器
Server
- Server 管理著所有的Service锯玛。它的主要作用是提供一個接口可以讓其它程序能夠訪問這個Service集合,同時維護所有service的生命周期等歼捐。
Server在Tomcat中的標準實現(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ù)組添加到最后蜕劝。然后啟動最新添加的Service
Service
Service 在Tomcat中的標準實現(xiàn)是StandardService
,Service 可以說是一個標準的服務(wù),擁有獨立的端口號。
在Service 中可以含有多個Connector和唯一的一個Container.這樣的設(shè)計模式可以允許 例如SSL加密過的請求和沒有經(jīng)過SSL加密的請求在一個APP中同時存在
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容器轰异,然后啟動這個容器岖沛,并將原有的容器的停止掉。Service 的setConnector
幾乎是同樣的套路
Container
Container 由四個子容器組成:
- Engine : 表示整個Catalina Servlet引擎搭独,是Container 只用最高層婴削,用來管理Host 或者Context的實現(xiàn)
- 如果你想攔截每一個到Servlet的請求,可以通過
- Host :表示一個Engine管理下的一個虛擬主機牙肝,比如你訪問的Localhost就是一個虛擬主機唉俗。作用是運行多個應(yīng)用
其處理過程可以總結(jié)如下:- 為特定的請求URL選擇一個Context容器
- 把Context容器綁定到線程中
- 判斷是否是一個異步請求
- 讓Context去處理這個請求
- Context執(zhí)行invoke方法嗤朴,進入管道中,由StandardContextValve(是ContextValve的標準實現(xiàn)類)處理
- Context:Context 是用來管理Servlet的容器虫溜,Context就對應(yīng)一個應(yīng)用雹姊。所以我們部署應(yīng)用時需要創(chuàng)建一個Context容器,Context負責管理Wrapper.
- Wrapper : 用來管理一個Servlet的生命周期
Connector
Connector 是Tomcat的連接器衡楞,主要任務(wù)是負責處理瀏覽器發(fā)送過來的請求容为,并創(chuàng)建一個Request和Response對象,用于和前端Client交換數(shù)據(jù)寺酪,然后產(chǎn)生一個線程坎背,并將Request對象和Response對象傳遞給線程,后面對這兩個線程的處理就是Container的事情了
- 實例化Connector寄雀,構(gòu)造一個Connector對象
- 調(diào)用Connector的initIntenal方法得滤,初始化Connetor
- 調(diào)用ProtocolHanlder的init方法,完成ProtocolHanlder的初始化盒犹。這個過程包括了創(chuàng)建線程池并創(chuàng)建一個線程處理瀏覽器請求
- 調(diào)用Connector的startIntenal方法懂更,啟動Connector
- 調(diào)用ProtocolHandler的start方法,啟動Protocolhanlder
- 調(diào)用MapperListener的start方法急膀,啟動監(jiān)聽器程序
不同于Container ,Connector是一個實現(xiàn)類.其相當于一個容器處理基于Http的請求
沮协。CoyoteAdapter,是connector和container的橋梁,經(jīng)過這一步,請求就從connector傳遞到container中里了卓嫂。Adapter
要注意的是:最先處理請求的Request是org.apache.coyote.Request類型慷暂,這是一個Tomcat中一個輕量級對象,完成基本的請求處理后很容易被JVM回收晨雳,那為什么不直接交給Connector.Request對象處理呢行瑞?由于后者是Servlet容器真正傳遞的對象其完成的職責比前者復(fù)雜,這里使用org.apache.coyote.Request主要減輕后者的任務(wù)負擔餐禁,出于性能考慮才這么設(shè)計血久。
從connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);這句代碼中可以知道下一步的處理需要交給Container容器了。
Context容器和Wrapper
Wrapper 接口是Context的抽象接口
Context的啟動:
Context的啟動過程就是加載整個類資源文件和打開子容器帮非,以及pipeline的過程氧吐。
StandardContextValve的invoke 方法會通過request得到相應(yīng)的ContextWrapper,在這個過程中如果沒有發(fā)生異常,服務(wù)端會向client 發(fā)送一個ack響應(yīng)
StandardContext的處理流程可以用下面的圖來簡化:
- StandardContext的addServlet會添加一個Servlet類,并通過Servlet名字分配一個ServletWrppar,如果沒有則為其新建一個末盔。通過這個Wrappar來管理這個Servlet筑舅。。
- Wrapper與Servlet息息相關(guān)庄岖,其中的loadServlet負責裝載Servlet.Wrapper是最底層
- Standard類主要負責初始化一個Servlet實例豁翎,并調(diào)用該實例的init方法角骤,然后通知感興趣的事件監(jiān)聽程序隅忿。用了Wrapper的invoke方法心剥,這個方法完成什么呢?
附錄: 一個HTTP請求是怎樣通過Tomcat到你的應(yīng)用中的
Http請求在Container中的傳遞流程