Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 粗淺看 Tomcat系統架構分析

粗淺看 Tomcat系統架構分析

編輯:關於Android編程

Tomcat的結構很復雜,但是Tomcat也非常的模塊化,找到了Tomcat最核心的模塊,就抓住了Tomcat的七寸

整體結構

Tomcat 總體結構圖

\

 

從上圖中可以看出Tomcat的心髒是兩個組件:Connector 和 Container,關於這兩個組件將在後面詳細介紹。Connector 組件是可以被替換,這樣可以提供給服務器設計者更多的選擇,因為這個組件是如此重要,不僅跟服務器的設計的本身,而且和不同的應用場景也十分相關,所以一個Container 可以選擇對應多個Connector。多個Connector和一個Container 就形成了一個Service,Service 的概念大家都很熟悉了,有了Service 就可以對外提供服務了,但是Service還要一個生存的環境,必須要有人能夠給她生命、掌握其生死大權,那就非Server莫屬了。所以整個Tomcat的生命周期由Server控制。

 

以Service 作為“婚姻”

我們將 Tomcat 中 Connector、Container 作為一個整體比作一對情 侶的話,Connector 主要負責對外交流,可以比作為 Boy,Container 主要處理 Connector 接受的請求,主要是處理內部事務,可以比作為 Girl。那麼這個 Service就是連接這對男女的結婚證了。是Service將它們連接在一起,共同組成一個家庭。當然要組成一個家庭還要很多其它的元素。

說白了,Service 只是在Connector 和 Container外面多包一層,把它們組裝在一起,向外面提供服務,一個Service可以設置多個Connector,但是只能有一個 Container 容器。這個 Service 接口的 方法列表如下:

①Service接口

\

 

從 Service接口中定義的方法中可以看出,它主要是為了關聯Connector和 Container,同時會初始化它下面的其它組件,注意接 口中它並沒有規定一定要控制它下面的組件的生命周期。所有組件的 生命周期在一個 Lifecycle 的接口中控制,這裡用到了一個重要的設 計模式,關於這個接口將在後面介紹。

Tomcat 中 Service接口的標准實現類是StandardService它不僅實現了 Service 借口同時還實現了 Lifecycle 接口,這樣它就可以控 制它下面的組件的生命周期了。StandardService 類結構圖如下:

②StandardService的類結構圖

\

 

從上圖中可以看出除了 Service接口的方法的實現以及控制組件生命周期的 Lifecycle 接口的實現,還有幾個方法是用於在事件監聽的 方法的實現,不僅是這個 Service 組件,Tomcat 中其它組件也同樣 有這幾個方法,這也是一個典型的設計模式,將在後面介紹。

 

下面看一下 StandardService 中主要的幾個方法實現的代碼,下面是setContainer和 addConnector 方法的源碼:

③StandardService. SetContainer

 

public void setContainer(Container container) {

Container oldContainer = this.container;

if ((oldContainer != null) && (oldContainer instanceof Engine))

((Engine) oldContainer).setService(null);

this.container = container;

if ((this.container != null) && (this.container instanceof Engine))

((Engine)  this.container).setService(this);

if (started && (this.container != null) && (this.container instanceof Lifecycle))

{

try {

((Lifecycle) this.container).start();

} catch (LifecycleException e) {

;

}

}

synchronized (connectors) {

for (int i = 0; i < connectors.length; i++)

connectors[i].setContainer(this.container);

}

if (started && (oldContainer != null) && (oldContainer instanceof Lifecycle)) {

try {

((Lifecycle)  oldContainer).stop();

} catch (LifecycleException e) {

;

}

}

support.firePropertyChange("container", oldContainer, this.container);
—————————————————————————————
}

 

這段代碼很簡單,其實就是先判斷當前的這個 Service 有沒有已經關 聯了 Container,如果已經關聯了,那麼去掉這個關聯關系——oldContainer.setService(null)。如果這個 oldContainer 已經被啟動 了,結束它的生命周期。然後再替換新的關聯、再初始化並開始這個新的 Container 的生命周期。最後將這個過程通知感興趣的事件監聽程序。這裡值得注意的地方就是,修改Container 時要將新的 Container關聯到每個Connector,還好 Container 和 Connector 沒有雙向關聯,不然這個關聯關系將會很難維護。

④StandardService. addConnector

 

public void addConnector(Connector connector) {

synchronized (connectors) {

connector.setContainer(this.container);

connector.setService(this);

Connector results[] = new Connector[connectors.length + 1];

System.arraycopy(connectors, 0, results, 0, connectors.length);

results[connectors.length] = connector;

connectors = results;

if (initialized) {

try {

connector.initialize();

} catch (LifecycleException e) {

e.printStackTrace(System.err);

}

}
 

if (started && (connector instanceof Lifecycle)) {

try {

((Lifecycle) connector).start();

} catch (LifecycleException e) {

;

}

}

support.firePropertyChange("connector", null, connector);

}

}

 

上面是 addConnector 方法,這個方法也很簡單,首先是設置關聯關 系,然後是初始化工作,開始新的生命周期。這裡值得一提的是,注 意 Connector 用的是數組而不是 List 集合,這個從性能角度考慮可 以理解,有趣的是這裡用了數組但是並沒有向我們平常那樣,一開始 就分配一個固定大小的數組,它這裡的實現機制是:重新創建一個當 前大小的數組對象,然後將原來的數組對象 copy 到新的數組中,這 種方式實現了類似的動態數組的功能,這種實現方式,值得我們以後 拿來借鑒。

最新的 Tomcat6 中 StandardService也基本沒有變化,但是從Tomcat5 開始 Service、Server 和容器類都繼承了MBeanRegistration接口,Mbeans 的管理更加合理。

以 Server 為“居”

 

前面說一對情侶因為 Service 而成為一對夫妻,有了能夠組成一個家 庭的基本條件,但是它們還要有個實體的家,這是它們在社會上生存 之本,有了家它們就可以安心的為人民服務了,一起為社會創造財富。

Server要完成的任務很簡單,就是要能夠提供一個接口讓其它程序能夠訪問到這個 Service 集合、同時要維護它所包含的所有 Service 的生命周期,包括如何初始化、如何結束服務、如何找到別人要訪問的 Service。還有其它的一些次要的任務,如您住在這個地方要向當 地政府去登記啊、可能還有要配合當地公安機關日常的安全檢查什麼 的。

Server的類結構圖如下:

①Server的類結構圖

\

 

它的標准實現類 StandardServer 實現了上面這些方法,同時也實現 了 Lifecycle、MbeanRegistration 兩個接口的所有方法,下面主要看 一下 StandardServer 重要的一個方法 addService的實現:

②StandardServer.addService

 

public void addService(Service service) {

service.setServer(this);

synchronized (services) {

Service results[] = new Service[services.length + 1];

System.arraycopy(services, 0, results, 0, services.length);

results[services.length] = service;

services = results;

if (initialized) {

try {

service.initialize();

} catch (LifecycleException e) {

e.printStackTrace(System.err);

}

}

if (started && (service instanceof Lifecycle)) {

try {

((Lifecycle) service).start();

} catch (LifecycleException e) {

;

}

}

support.firePropertyChange("service", null, service);

}

}

 

從上面第一句就知道了 Service和 Server是相互關聯的,Server也是和 Service 管理 Connector 一樣管理它,也是將 Service 放在 一個數組中,後面部分的代碼也是管理這個新加進來的 Service 的生 命周期。Tomcat6 中也是沒有什麼變化的。

組件的生命線“Lifecycle”

 

前面一直在說 Service 和 Server 管理它下面組件的生命周期,那它 們是如何管理的呢?

Tomcat 中組件的生命周期是通過Lifecycle 接口來控制的,組件只 要繼承這個接口並實現其中的方法就可以統一被擁有它的組件控制 了,這樣一層一層的直到一個最高級的組件就可以控制 Tomcat 中 所有組件的生命周期,這個最高的組件就是 Server,而控制 Server的是 Startup,也就是您啟動和關閉Tomcat。

下面是 Lifecycle 接口的類結構圖:

①Lifecycle類結構圖

\

除了控制生命周期的 Start 和 Stop 方法外還有一個監聽機制,在生命周期開始和結束的時候做一些額外的操作。這個機制在其它的框架中也被使用,如在Spring 中。關於這個設計模式會在後面介紹。

 

Lifecycle接口的方法的實現都在其它組件中,就像前面中說的,組件的生命周期由包含它的父組件控制,所以它的 Start 方法自然就是調用它下面的組件的 Start 方法,Stop 方法也是一樣。如在 Server 中 Start 方法就會調用Service組件的 Start方法,Server 的 Start方法代碼如下:

②StandardServer.Start

 

public void start() throws LifecycleException {

if (started) {

log.debug(sm.getString("standardServer.start.started"));

return;

}

lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,  null);

lifecycle.fireLifecycleEvent(START_EVENT,  null);

started = true;

synchronized (services) {

for (int i = 0; i < services.length; i++) {

if (services[i] instanceof Lifecycle)

((Lifecycle) services[i]).start();

}

}

lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

}
監聽的代碼會包圍 Service 組件的啟動過程,就是簡單的循環啟動所有 Service組件的Start 方法,但是所有Service必須要實現

 

Lifecycle接口,這樣做會更加靈活。

Server的 Stop 方法代碼如下:

③StandardServer.Stop

 

public void stop() throws LifecycleException {

if (!started)

return;

lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);

lifecycle.fireLifecycleEvent(STOP_EVENT,  null);

started = false;

for (int i = 0; i < services.length; i++) {

if (services[i] instanceof Lifecycle)

((Lifecycle) services[i]).stop();

}

lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);

}

 

它所要做的事情也和Start方法差不多。

Connector組件

Connector組件是Tomcat中兩個核心組件之一,它的主要任務是負責接收浏覽器的發過來的tcp連接請求,創建個Request 和處理這個請求並把產生的Request 和 Response對象傳給處理這個請求的線程,處理這個請求的線程就是Container 組件要做的事了。

 

由於這個過程比較復雜,大體的流程可以用下面的順序圖來解釋:

①Connector處理一次請求順序圖

\

 

Tomcat5 中默認的 Connector 是 Coyote,這個 Connector 是可以選擇替換的。Connector 最重要的功能就是接收連接請求然後分配線 程讓 Container 來處理這個請求,所以這必然是多線程的,多線程的處理是 Connector 設計的核心。Tomcat5將這個過程更加細化,它將 Connector劃分成 Connector、Processor、Protocol, 另外Coyote也定義自己的Request 和 Response對象。

下面主要看一下 Tomcat 中如何處理多線程的連接請求,先看一下Connector的主要類圖:

② Connector的主要類圖

\

 

看一下HttpConnector的Start 方法:

③HttpConnector.Start

 

public void start() throws LifecycleException {

if (started)

throw new LifecycleException

(sm.getString("httpConnector.alreadyStarted"));

threadName = "HttpConnector[" + port + "]";

lifecycle.fireLifecycleEvent(START_EVENT,  null);

started = true;

threadStart();

while (curProcessors < minProcessors) {

if ((maxProcessors > 0) && (curProcessors >= maxProcessors))

break;

HttpProcessor processor = newProcessor();

recycle(processor);

}

}

 

threadStart()執行就會進入等待請求的狀態,直到一個新的請求到來才會激活它繼續執行,這個激活是在HttpProcessor 的 assign 方法中,這個方法是代碼如下 :

④ HttpProcessor.assign

 

synchronized void assign(Socket socket) {

while (available) {

try {

wait();

} catch (InterruptedException e) {
 
—————————————————————————————
}

}

this.socket = socket;

available = true;

notifyAll();

if ((debug >= 1) && (socket != null))

log(" An incoming request is being assigned");

}

 

創建 HttpProcessor 對象是會把 available 設為 false,所以當請求 到來時不會進入 while循環,將請求的socket 賦給當期處理的 socket,並將 available設為true,當 available設為true 是 HttpProcessor的 run方法將被激活,接下去將會處理這次請求。

Run方法代碼如下:

⑤HttpProcessor.Run

 

public void run() {

while (!stopped) {

Socket socket = await();

if (socket == null)

continue;

try {

process(socket);

} catch (Throwable t) {

log("process.invoke", t);

}

connector.recycle(this);

}

—————————————————————————————
synchronized (threadSync) {

threadSync.notifyAll();

}

}

 

解析 socket 的過程在 process 方法中,process 方法的代碼片段如 下:

⑥HttpProcessor.process

 

private void process(Socket socket) {

boolean ok = true;

boolean finishResponse = true;

SocketInputStream input = null;

OutputStream output = null;

try {

input = new SocketInputStream(socket.getInputStream(),connector.getBufferSize());
} catch (Exception e) {

log("process.create", e);

ok = false;

}

keepAlive = true;

while (!stopped && ok && keepAlive) {

finishResponse = true;

try {

request.setStream(input);

request.setResponse(response);

output = socket.getOutputStream();

response.setStream(output);

response.setRequest(request);

((HttpServletResponse)  response.getResponse())

 
—————————————————————————————
.setHeader("Server", SERVER_INFO);

} catch (Exception e) {

log("process.create", e);

ok = false;

}

try {

if (ok) {

parseConnection(socket);

parseRequest(input, output);

if (!request.getRequest().getProtocol().startsWith("HTTP/0"))

parseHeaders(input);

if (http11) {

ackRequest(output);

if  (connector.isChunkingAllowed())

response.setAllowChunking(true);

}

}

try {

((HttpServletResponse)  response).setHeader

("Date",  FastHttpDateFormat.getCurrentDate());

if (ok) {

connector.getContainer().invoke(request, response);

}

}

try {

shutdownInput(input);

socket.close();

} catch (IOException e) {

;

} catch (Throwable e) {
 

log("process.invoke", e);

}

socket = null;

}

 

當 Connector將 socket 連接封裝成 request 和 response 對象後 接下來的事情就交給 Container 來處理了。

Servlet容器“Container”

Container是容器的父接口,所有子容器都必須實現這個接口,Container容器的設計用的是典型的責任鏈的設計模式,它有四個子 容器組件構成,分別是:Engine、Host、Context、Wrapper,這四個組件不是平行的,而是父子關系,Engine包含 Host,Host 包含 Context,Context 包含 Wrapper。通常一個 Servlet class 對應一個 Wrapper,如果有多個 Servlet 就可以定義多個 Wrapper,如果有多 個 Wrapper 就要定義一個更高的Container 了,如 Context, Context 通常就是對應下面這個配置:

①Server.xml

 


②容器的總體設計

 

 

Context 還可以定義在父容器Host中,Host 不是必須的,但是要運行 war 程序,就必須要 Host,因為 war 中必有 web.xml 文件, 這個文件的解析就需要 Host 了,如果要有多個 Host 就要定義一個 top 容器 Engine 了。而 Engine 沒有父容器了,一個 Engine 代表 一個完整的 Servlet 引擎。

那麼這些容器是如何協同工作的呢?先看一下它們之間的關系圖:

①四個容器的關系圖

\

 

當 Connector接受到一個連接請求時,將請求交給Container, Container是如何處理這個請求的?這四個組件是怎麼分工的,怎麼 把請求傳給特定的子容器的呢?又是如何將最終的請求交給 Servlet處理。下面是這個過程的時序圖:

②Engine和Host 處理請求的時序圖

\

 

這裡看到了 Valve 是不是很熟悉,沒錯 Valve 的設計在其他框架中 也有用的,同樣 Pipeline的原理也基本是相似的,它是一個管道,Engine和 Host都會執行這個 Pipeline,您可以在這個管道上增加 任意的 Valve,Tomcat 會挨個執行這些Valve,而且四個組件都會 有自己的一套 Valve 集合。您怎麼才能定義自己的Valve 呢?在server.xml 文件中可以添加,如給 Engine 和 Host 增加一個 Valve如下:

③Server.xml

 





………





…………




 

StandardEngineValve和 StandardHostValve是 Engine和 Host的默認的 Valve,它們是最後一個Valve 負責將請求傳給它們的子 容器,以繼續往下執行。

前面是 Engine和 Host容器的請求過程,下面看Context 和Wrapper 容器時如何處理請求的。下面是處理請求的時序圖:

④Context 和wrapper 的處理請求時序圖

\

 

從 Tomcat5 開始,子容器的路由放在了 request 中,request 中保 存了當前請求正在處理的 Host、Context 和 wrapper。

③Engine 容器

 

Engine容器比較簡單,它只定義了一些基本的關聯關系,接口類圖如下:

①Engine 接口的類結構

\

 

它的標准實現類是StandardEngine,這個類注意一點就是 Engine沒有父容器了,如果調用 setParent 方法時將會報錯。添加子容器也 只能是 Host 類型的,代碼如下:

②StandardEngine. addChild

 

public void addChild(Container child) {

if (!(child instanceof Host))

throw new IllegalArgumentException

(sm.getString("standardEngine.notHost"));

super.addChild(child);

}

public void setParent(Container container) {

throw new IllegalArgumentException

(sm.getString("standardEngine.notParent"));

}

 

它的初始化方法也就是初始化和它相關聯的組件,以及一些事件的監聽。

④Host容器

 

Host是 Engine 的字容器,一個Host在 Engine中代表一個虛擬主機,這個虛擬主機的作用就是運行多個應用,它負責安裝和展開這些應用,並且標識這個應用以便能夠區分它們。它的子容器通常是Context,它除了關聯子容器外,還有就是保存一個主機應該有的信 息。

①Host 相關的類圖

\

 

從上圖中可以看出除了所有容器都繼承的ContainerBase外, StandardHost還實現了Deployer 接口,上圖清楚的列出了這個接口的主要方法,這些方法都是安裝、展開、啟動和結束每個web application。

Deployer 接口的實現是 StandardHostDeployer,這個類實現了的最要的幾個方法,Host 可以調用這些方法完成應用的部署等。

⑤Context容器

 

Context 代表 Servlet 的 Context,它具備了 Servlet 運行的基本環 境,理論上只要有 Context 就能運行Servlet 了。簡單的 Tomcat可以沒有 Engine 和 Host。

Context 最重要的功能就是管理它裡面的Servlet實例,Servlet 實 例在 Context 中是以Wrapper 出現的,還有一點就是 Context 如 何才能找到正確的Servlet 來執行它呢?Tomcat5以前是通過一 個 Mapper 類來管理的,Tomcat5 以後這個功能被移到了request 中,在前面的時序圖中就可以發現獲取子容器都是通過request 來分配的。

Context 准備 Servlet 的運行環境是在 Start 方法開始的,這個方法 的代碼片段如下:

①StandardContext.start

 

public synchronized void start() throws LifecycleException {

………

if( !initialized ) {

try {

init();

} catch( Exception ex ) {

throw new LifecycleException("Error initializaing ", ex);

}

}

………

lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,   null);

setAvailable(false);

setConfigured(false);

boolean ok = true;

File configBase = getConfigBase();

if (configBase != null) {

if (getConfigFile() == null) {

File file = new File(configBase, getDefaultConfigFile());

setConfigFile(file.getPath());

try {

File appBaseFile = new File(getAppBase());

if (!appBaseFile.isAbsolute()) {

appBaseFile = new File(engineBase(), getAppBase());

}

String appBase = appBaseFile.getCanonicalPath();

String basePath =

(new  File(getBasePath())).getCanonicalPath();

if (!basePath.startsWith(appBase)) {

Server server = ServerFactory.getServer();

((StandardServer)  server).storeContext(this);

}

} catch (Exception e) {

log.warn("Error storing config file", e);

}

} else {

try {

String canConfigFile =  (new File(getConfigFile())).getCanonicalPath();
if (!canConfigFile.startsWith (configBase.getCanonicalPath())) {

File file = new File(configBase, getDefaultConfigFile());

if (copy(new File(canConfigFile), file)) {
 
—————————————————————————————
setConfigFile(file.getPath());

}

}

} catch (Exception e) {

log.warn("Error setting config file", e);

}

}

}
………

Container children[] = findChildren();

for (int i = 0; i < children.length; i++) {

if (children[i] instanceof Lifecycle)

((Lifecycle)  children[i]).start();

}

if (pipeline instanceof Lifecycle)

((Lifecycle) pipeline).start();

………

}

 

它主要是設置各種資源屬性和管理組件,還有非常重要的就是啟動子容器和 Pipeline。

我們知道 Context 的配置文件中有個 reloadable 屬性,如下面配置:

②Server.xml

 


 

當這個 reloadable 設為 true 時,war被修改後 Tomcat 會自動的重新加載這個應用。如何做到這點的呢? 這個功能是在StandardContext的 backgroundProcess 方法中實現的,這個方法的代碼如下:

③StandardContext. backgroundProcess

 

public void backgroundProcess() {

if (!started) return;

count = (count + 1) % managerChecksFrequency;

if ((getManager() != null) && (count == 0)) {

try {

getManager().backgroundProcess();

} catch ( Exception x ) {

log.warn("Unable to perform background process on manager",x);

}

}

if (getLoader() != null) {

if (reloadable && (getLoader().modified())) {

try {

Thread.currentThread().setContextClassLoader

(StandardContext.class.getClassLoader());

reload();

} finally {

if (getLoader() != null) {

Thread.currentThread().setContextClassLoader
 

(getLoader().getClassLoader());

}

}

}

if (getLoader() instanceof WebappLoader) {

((WebappLoader)  getLoader()).closeJARs(false);

}

}

}

 

它會調用 reload 方法,而 reload方法會先調用 stop方法然後再調用 Start 方法,完成Context 的一次重新加載。可以看出執行reload方法的條件是reloadable 為 true 和應用被修改,那麼這個backgroundProcess 方法是怎麼被調用的呢?

這個方法是在 ContainerBase 類中定義的內部類ContainerBackgroundProcessor被周期調用的,這個類是運行在一個後台線程中,它會周期的執行 run 方法,它的 run 方法會周期調 用所有容器的 backgroundProcess 方法,因為所有容器都會繼承ContainerBase類,所以所有容器都能夠在backgroundProcess 方 法中定義周期執行的事件。

⑥Wrapper容器

 

Wrapper 代表一個Servlet,它負責管理一個 Servlet,包括的 Servlet的裝載、初始化、執行以及資源回收。Wrapper是最底層的 容器,它沒有子容器了,所以調用它的 addChild 將會報錯。

Wrapper 的實現類是 StandardWrapper,StandardWrapper 還實現 了擁有一個 Servlet 初始化信息的ServletConfig,由此看出 StandardWrapper 將直接和Servlet的各種信息打交道。

下面看一下非常重要的一個方法loadServlet,代碼片段如下:

①StandardWrapper.loadServlet
public synchronized Servlet loadServlet() throws ServletException {

………

Servlet servlet;

try {

………

ClassLoader classLoader = loader.getClassLoader();

………

Class classClass = null;

………

servlet = (Servlet) classClass.newInstance();

if ((servlet instanceof ContainerServlet) &&

(isContainerProvidedServlet(actualClass)  ||

((Context)getParent()).getPrivileged() )) {

((ContainerServlet)  servlet).setWrapper(this);

}
 

classLoadTime=(int) (System.currentTimeMillis() -t1);

try {


instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,servlet);

if( System.getSecurityManager() != null) {

Class[] classType = new Class[]{ServletConfig.class};

Object[] args = new Object[]{((ServletConfig)facade)};

SecurityUtil.doAsPrivilege("init",servlet,classType,args);

} else {

servlet.init(facade);

}

if ((loadOnStartup >= 0) && (jspFile != null)) {

………

if( System.getSecurityManager() != null) {

Class[] classType = new Class[]{ServletRequest.class,

ServletResponse.class};

Object[] args = new Object[]{req, res};

SecurityUtil.doAsPrivilege("service",servlet,classType,args);

} else {

servlet.service(req, res);

}

}


instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,servlet);

………

return servlet;

}

它基本上描述了對Servlet 的操作,當裝載了Servlet後就會調用Servlet的 init方法,同時會傳一個StandardWrapperFacade對象給Servlet,這個對象包裝了StandardWrapper,ServletConfig 與它們的關系圖如下:

②ServletConf 與StandardWrapperFacade、StandardWrapper的關系

\

 

Servlet可以獲得的信息都在StandardWrapperFacade封裝,這些信息又是在 StandardWrapper 對象中拿到的。所以 Servlet 可以通 過 ServletConfig 拿到有限的容器的信息。

當 Servlet 被初始化完成後,就等著 StandardWrapperValve 去調用 它的 service 方法了,調用 service 方法之前要調用 Servlet 所有的 filter。

Tomcat中其它組件

Tomcat 還有其它重要的組件,如安全組件security、logger 日 志組件、session、mbeans、naming 等其它組件。這些組件共同為Connector和 Container 提供必要的服務。

業務思想

關於Tomcat服務器的了解,算是很長時間的了解了,很好用。本博文中關於Tomcat系統架構的學習和總結,算是個人的理解,寫一寫總結總感覺很有必要,收獲頗多。多加使用,方感頗深。大家有什麼好的理解,歡迎交流!

  1. 上一頁:
  2. 下一頁:
Copyright © Android教程網 All Rights Reserved