深入理解Tomcat系列之一:系統架構(轉)
前言
Tomcat是Apache基金組織下的開源專案,性質是一個Web伺服器。下面這種情況很普遍:在eclipse床架一個web專案並部署到Tomcat中,啟動tomcat,在瀏覽器中輸入一個類似http://localhost:8080/webproject/anyname.jsp
的url,然後就可以看到我們寫好的jsp頁面的內容了。一切都是那麼自然和順理成章,然而這一切都是源於tomcat帶給我們的,那麼在tomcat背後,這一切又是怎麼樣發生的呢?帶著對tomcat工作原理的好奇心,我決定研究一下tomcat的原始碼,然而部署原始碼環境的過程卻讓我心灰意冷,本著搞不定我還真不信的熱情,折騰了一個晚上+一個早上,終於把原始碼原始碼環境搭建好了。
為了讓文章顯得更有條理性,我將從以下幾個方面說明Tomcat的工作流程:
- 搭建Tomcat原始碼環境指導
- Tomcat的系統架構
- Tomcat中的核心元件說明
- Servlet工作原理
- 一個例子
Tomcat的系統架構
首先我們從一個巨集觀的角度來看一下Tomcat的系統的架構:
從這張圖中可以看到,Tomcat的核心元件就兩個Connector和Container(後面還有詳細說明),一個Connector+一個Container構成一個Service,Service就是對外提供服務的元件,有了Service元件Tomcat就可以對外提供服務了,但是光有服務還不行,還得有環境讓你提供服務才行,所以最外層的Server就為Service提供了生存的土壤。那麼這些個元件到底是幹嘛用的呢?Connector是一個聯結器,主要負責接收請求並把請求交給Container,Container就是一個容器,主要裝的是具體處理請求的元件。Service主要是為了關聯Container與Connector,一個單獨的Container或者一個單獨的Connector都不能完整處理一個請求,只有兩個結合在一起才能完成一個請求的處理。Server這是負責管理Service集合,從圖中我們看到一個Tomcat可以提供多種服務,那麼這些Serice就是由Server來管理的,具體的工作包括:對外提供一個介面訪問Service,對內維護Service集合,維護Service集合又包括管理Service的生命週期、尋找一個請求的Service、結束一個Service等。以上就是對Tomcat的核心元件的簡要說明,下面我們詳細看看每一個元件的執行流程:
Server
上面說Server是管理Service介面的,Server是Tomcat的頂級容器,是一個介面,Server介面的標準實現類是StandardServer類,在Server介面中有許多方法,我們重點關注兩個方法:addService()和findService(String)。我們先來看看Server介面的全貌:
接著看看addService()和findService(String)的實現程式碼:
程式碼清單1-1:
/** * Add a new Service to the set of defined Services. * * @param service The Service to be added */ @Override 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 (getState().isAvailable()) { try { service.start(); } catch (LifecycleException e) { // Ignore } } // Report this property change to interested listeners support.firePropertyChange("service", null, service); } }
可以看到,Server使用一個數組來管理Service的,每新增一個Service就把原來的Service拷貝到一個新的陣列中,再把新的Service放入Service陣列中。所以Server與Service是關聯在一起的,那麼後面的getState().isAvailable()
是幹嘛的呢?判斷狀態是否無效,從而決定是否執行service方法。這裡說到了狀態,就不得不說Tomcat管理各元件生命週期的Lifecycle介面了:
Lifecycle介面
Tomcat中的元件都交給這個介面管理,但是具體元件的生命週期是由包含元件的父容器來管理的,Tomcat中頂級容器管理著Service的生命週期,Service容器又是Connector和Container的父容器,所以這兩個元件的生命週期是由Service管理的,Container也有子容器,所以管理著這些子容器的生命週期。這樣,只要所有元件都實現了Lifecycle介面,從頂層容器Server開始,就可以控制所有容器的生命週期了。Lifecycle介面中定義了很多狀態,在api中詳細說明了呼叫不同方法後的狀態轉變,同時定義了不同的方法,這些方法在執行後狀態會發生相應的改變,在Lifecycle介面中定義瞭如下方法:
在StandServer中實現了startInernal()方法,就是迴圈啟動StandServer管理的Service的過程,Tomcat的Service都實現了Lifecycle介面,所以被管理的Service都將被通知到,從而執行start()方法,startIntenal()方法是這樣的:
程式碼清單1-2:
/**
* Start nested components ({@link Service}s) and implement the requirements
* of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
*
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
@Override
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
// Start our defined Services
synchronized (services) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}
現在所有的Service就會收到通知繼而執行start方法。如果一個Service不允許被使用將會丟擲一個LifecycleException異常。
stopIntenal()會通知所有Service執行stop方法,具體處理流程與startIntenal()方法類似。這個執行過程涉及一個非常重要的設計模式,就是觀察者模式。
現在我們已經能夠知道了容器通過Lifecycle介面管理容器的生命週期,那麼在父容器的狀態改變具體是怎麼樣通知給子容器的呢?回到程式碼清單1-2,我們注意到有一個fireLifecycleEvent()
方法,fireLifecycleEvent()的執行流程如下:
- 呼叫LifecycleBase的fireLifecycleEvent(LifecycleListener listener)方法,LifecycleBase是一個抽象類,實現了Lifecycle介面
- 繼續呼叫LifecycleSupport(是一個輔助完成對已經註冊監聽器的事件通知類,不可被繼承,使用final)的fireLifecycleEvent(String type, Object data)方法
- 完成事件通知
fireLifecycleEvent(String type, Object data)的方法如下:
程式碼清單1-3:
/**
* Notify all lifecycle event listeners that a particular event has
* occurred for this Container. The default implementation performs
* this notification synchronously using the calling thread.
*
* @param type Event type
* @param data Event data
*/
public void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
LifecycleListener interested[] = listeners;
for (int i = 0; i < interested.length; i++)
interested[i].lifecycleEvent(event);
}
所以,具體事件的通知是由LifecycleListener介面的lifecycleEvent方法完成的,各實現類可以根據不同的情況實現不同的事件監聽邏輯
Service
Service是具體提供服務的介面,一個Service包裝了Connector和一個Container,在Tomcat中這點是如何實現的呢?Service是一個介面,其標準實現類是StandardService,下面是這兩個類的鳥瞰圖:
這裡,我們只關心與Connector和Container最緊密的方法:setContainer()和addConnector()方法,先看一下setContainer()方法的原始碼:
程式碼清單2-1:
/**
* Set the <code>Container</code> that handles requests for all
* <code>Connectors</code> associated with this Service.
*
* @param container The new Container
*/
@Override
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 (getState().isAvailable() && (this.container != null)) {
try {
this.container.start();
} catch (LifecycleException e) {
// Ignore
}
}
if (getState().isAvailable() && (oldContainer != null)) {
try {
oldContainer.stop();
} catch (LifecycleException e) {
// Ignore
}
}
// Report this property change to interested listeners
support.firePropertyChange("container", oldContainer, this.container);
}
從程式碼中可以看到這個方法主要的任務是設定一個Container容器來處理一個或者多個Connector傳送過來的請求。首先判斷當前的Service是否已經關聯了Container容器,如果已經關聯了就去除這個關聯關係。如果原來的Container容器已經啟動了就終止其生命週期,結束執行並設定新的關聯關係,這個新的Container容器開始新的生命週期。最後把這個過程通知給感興趣的事件監聽程式。
下面看看addConnector的方法:
程式碼清單2-2:
/**
* Add a new Connector to the set of defined Connectors, and associate it
* with this Service's Container.
*
* @param connector The Connector to be added
*/
@Override
public void addConnector(Connector connector) {
synchronized (connectors) {
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 (getState().isAvailable()) {
try {
connector.start();
} catch (LifecycleException e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
// Report this property change to interested listeners
support.firePropertyChange("connector", null, connector);
}
}
執行過程也比較清楚:用一個同步程式碼塊包住connectors陣列,首先設定connector與container和service的關聯關係,然後讓connector開始新的生命週期,最後通知感興趣的事件監聽程式。注意到Connector的管理和Server管理Service一樣都使用了陣列拷貝並把新的陣列賦給當前的陣列,從而間接實現了動態陣列。之所以使用陣列我想可能是出於效能的考慮吧。
http://blog.csdn.net/u011116672/article/details/50993980
相關推薦
深入理解Tomcat系列之一:系統架構(轉)
前言 Tomcat是Apache基金組織下的開源專案,性質是一個Web伺服器。下面這種情況很普遍:在eclipse床架一個web專案並部署到Tomcat中,啟動tomcat,在瀏覽器中輸入一個類似http://localhost:8080/webproject/anyname.jsp的url,然後就可以看到
深入理解Tomcat系列之一:系統架構
chan 比較 efi 多個 soci 重點 之一 處理流程 containe 前言: Tomcat是Apache基金組織下的開源項目,性質是一個Web服務器。下面這種情況很普遍:在eclipse床架一個web項目並部署到Tomcat中,啟動tomcat,在瀏覽器中輸入一個
深入理解Spring系列之一:開篇
Spring經過大神們的構思、編碼,日積月累而來,所以,對其程式碼的理解也不是一朝一夕就能快速完成的。原始碼學習是枯燥的,需要堅持!堅持!堅持!當然也需要技巧,第一遍學習的時候,不用關注全部細節,不重要的程式碼可以先忽略掉,達到理解大體的架子及流程,避免第一次就陷入某個坑
深入理解 RecyclerView 系列之一:ItemDecoration
RecyclerView 已經推出了一年多了,日常開發中也已經徹底從 ListView 遷移到了 RecyclerView,但前兩天有人在一個安卓群裡面問了個關於最頂上的 item view 加蒙層的問題,被人用 ItemDecoration 完美解決。此時我發現自己對
五大常用演算法之一:分治演算法(轉)
分治演算法 一、基本概念 在電腦科學中,分治法是一種很重要的演算法。字面上的解釋是“分而治之”,就是把一個複雜的問題分成兩個或更多的相同或相似的子問題,再把子問題分成更小的子問題……直到最後子問題可以簡單的直接求解,原問題的解即子問題的解的合併。這個技巧是很多高效演算法的基礎,如排序演算法(快速排序,
深入理解Tomcat系列之五:Context容器和Wrapper容器
ssa stream servlet實例 可用 igel sse ould rip alt 前言 Context容器是一個Web項目的代表,主要管理Servlet實例,在Tomcat中Servlet實例是以Wrapper出現的。如今問題是怎樣才幹通過C
深入理解Tomcat系列之七:詳解URL請求
前言 這裡分析一個實際的請求是如何在Tomcat中被處理的,以及最後是怎麼樣找到要處理的Servlet的?當我們在瀏覽器中輸入http://hostname:port/contextPath/servletPath,前面的hostname與port用於建立tc
深入理解Tomcat系列之六 Servlet工作原理
前言Servlet是Web開發中的核心技術,作為一名合格的開發人員,就必須清楚Servlet的工作原理。本章沒有對Servlet技術本身進行詳細的說明,只是針對開發過程中一次Servlet的請求的處理過程進行分析的。Servlet實際上就是一個java類,只不過可以和
深入理解Tomcat系列之三 Connector
前言Connector是Tomcat的聯結器,其主要任務是負責處理瀏覽器傳送過來的請求,並建立一個Request和Response的物件用於和瀏覽器交換資料,然後產生一個執行緒用於處理請求,Connector會把Request和Response物件傳遞給該執行緒,該執
深入理解Tomcat系列之七 詳解URL請求
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
深入理解Tomcat系列之四 Engine和Host容器
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
深入理解ajax系列之一-XHR物件
概述 ajax是asynchronous javascript and XML的簡寫,中文翻譯是非同步的javascript和XML,這一技術能夠向伺服器請求額外的資料而無須解除安裝頁面,會帶來更好的使用者體驗。雖然名字中包含XML,但ajax通訊與資料格
架構設計:系統儲存(18)——Redis叢集方案:高效能
1、概述 通過上一篇文章(《架構設計:系統儲存(17)——Redis叢集方案:高可用》)的內容,Redis主從複製的基本功能和進行Redis高可用叢集監控的Sentinel基本功能基本呈現給了讀者。雖然本人並不清楚上一篇根據筆者實際工作經驗所撰寫的文章有什麼重
架構設計:系統儲存(29)——分散式檔案系統Ceph(管理)
3-3. Ceph常用命令 Ceph檔案系統提供的運維命令主要是按照Ceph中的工作角色/工作職責進行劃分的,例如有一套專門對OSD節點進行管理的命令、有一套專門對PG進行管理的命令、有一套專門對MDS角色進行管理的命令……您可以使用ceph –help進行命
《深入理解C指針》學習筆記(1)--- 指針之外
結構 def form 學習 編程 stdlib.h struct 一個 char C語言從誕生之初就非常善於和硬件打交道,經過這麽多年的發展之後,其靈活性和超強的特征是受到幾乎所有程序員的肯定。C語言的這種靈活性很大一部分程度來源與C指針,指針為C語言動態操控內存提供
Android系統架構(一)
查詢 核心 手機 例如 ava 模塊 api 操作系統 運行 一、Android系統版本簡介 Android操作系統已占據了手機操作系統的大半壁江山,截至本文寫作時,Android操作系統系統版本及其詳細信息,已發生了變化,具體信息見下表,當然也可以訪問https:
Silverlight & Blend動畫設計系列四:傾斜動畫(SkewTransform)
圖形 wid onu alt 文件 amp val 設計工具 現實生活 Silverlight中的傾斜變化動畫(SkewTransform)能夠實現對象元素的水平、垂直方向的傾斜變化動畫效果。我們現實生活中的傾斜變化效果是非常常見的,比如翻書的紙張效果,關門開門的時候門縫圖
Silverlight & Blend動畫設計系列一:偏移動畫(TranslateTransform)
gif 用戶 pre class 拖拽 width 新用戶 board 動畫效果 用戶界面組件、圖像元素和多媒體功能可以讓我們的界面生動活潑,除此之外,Silverlight還具備動畫功能,它可以讓應用程序“動起來”。實際上,英文中Animation這個單詞的意思是給某物帶
Silverlight & Blend動畫設計系列二:旋轉動畫(RotateTransform)
target width duration pac 操作 縮放 () rop pri Silverlight的基礎動畫包括偏移、旋轉、縮放、傾斜和翻轉動畫,這些基礎動畫毫無疑問是在Silverlight中使用得最多的動畫效果,其使用也是非常簡單的。相信看過上一篇《偏移動畫(
Silverlight & Blend動畫設計系列七:模糊效果(BlurEffect)與陰影效果(DropShadowEffect)
home 鼠標 color amp pos function soft mage double 原文:Silverlight & Blend動畫設計系列七:模糊效果(BlurEffect)與陰影效果(DropShadowEffect) 模糊效果(BlurEffec