本文即將介紹的是Server.xml - Tomcat的主配置文件。該文件存放在安裝目錄下的conf文件夾中。爲了讓大家有個直觀的認識,在此將Tomcat7的默認配置摘錄如下:

type="org.apache.catalina.UserDatabase"

description="User database that can be updated and saved"

factory="org.apache.catalina.users.MemoryUserDatabaseFactory"

pathname="conf/tomcat-users.xml" />

connectionTimeout="20000"

redirectPort="8443" />

resourceName="UserDatabase"/>

unpackWARs="true" autoDeploy="true">

prefix="localhost_access_log." suffix=".txt"

pattern="%h %l %u %t "%r" %s %b" />

去掉元素屬性,稍加整理,配置文件就變成了下面這樣:

根據Tomcat自身的分類,上面這些元素可以分成四種:

頂級元素 - 即Server和Service,前者是本配置文件的根節點,後者則起到了一個包裹內部組件的作用。換句話說,它們都屬於“單純的、不具有具體職能的配置節點”。

容器 - Tomcat內真正負責處理請求並返回結果的組件。

Connector - Connector(接頭)是一個特殊的組件,如果說整個Tomcat是一堵牆,它就是安裝在牆上的插座。外部的客戶端通過這些插座來跟Tomcat建立聯繫。

嵌套組件 - 這是一些嵌套在各種容器內部的組件,有些可以放在任意一層容器內,例如Listener;有些只能放在固定的位置,例如GlobalNamingResources。

下面將選擇性地介紹這些元素。

頂級元素

Server

一個Tomcat只有一個Server.xml,即一個Tomcat實例只有一個Server。從實現來看,作爲Server.xml的根節點,它不是一個容器,它只是單純地扮演着一個包裹的角色。從命名來看,它又可以是整個Tomcat所有容器和作用於所用容器的組件的混合體。在此,我們把它當做是Tomcat實例本身。

單機Tomcat實例個數

大部分情況下我們在一臺服務器/雲服務器上只跑一個tomcat,但也有兩種特例

一是爲了測試,在一臺機器上跑多個Tomcat,用以模擬多臺服務器多個應用交互的效果。

二是通過nginx+多個tomcat組成負載均衡集羣,以達到以下目的:

1、在32位系統上,由於尋址空間、內核預留內存等我們不太需要關心的機制,單個進程可以使用的內存上限大概是1.5G~2G(windows)和2G~3G(linux)。因此,大內存服務器上如果要充分利用內存就只能多開Tomcat。理論上64位系統沒有這個問題。但由於內存指針膨脹和數據類型對齊補白等同樣不太需要關心的機制,運行在64位系統上的JVM需要消耗更多的內存(《深入理解Java虛擬機》),因此,多數應用還是採用在32位系統上部署虛擬集羣的方式。

2、配置太大的內存可能會降低JVM進行垃圾回收的頻率,也就意味着每一次垃圾回收都是一個耗時日久的大工程,甚至可能導致宕機。一般建議單個JVM最大內存不超過1.5G。

3、從穩定性上考慮,個別tomcat掛了也不會導致服務下線。

Tomcat 之圖文解析 Server.xml 配置

★ Server元素屬性

Server可配置的屬性很少。根據上面摘錄的默認配置,Server會偵聽localhost的TCP端口8005,當該端口接收到字符串"SHUTDOWN"時,即執行關閉Tomcat操作。

★ Server 的嵌套組件

Server有兩種特有的組件,一個是GlobalNamingResources(全局命名資源),一個是Service(服務)。除此之外,還可以有Listener(監聽器)這種可以作用於不同層次容器的組件。Server默認配置了六種Listener,其作用會在後面介紹。配置在Server這一層的Listener對所有容器起作用。

Tomcat 之圖文解析 Server.xml 配置

Service

Service是另一個混合體。一個Service就是一個完整的服務,負責將若干個Connector和一個Engine(引擎)包裹在一起。除此之外,Service還可以配置一個Executor(共享線程池)用於管理所有Connector的線程數量。

★ service元素屬性

...

Service的屬性比Server更少,一般只用到了name這個屬性。默認配置定義了一個名爲“Catalina”的 Service。什麼是Catalina呢?Cataline是一個太平洋小島的名字,而Tomcat開發團隊的一個核心人員Craig McClanahan喜歡這個小島,所以...

★ Service 的嵌套組件

如圖所示,Service有Executor、Connector和Engine三種組件。其中,每個Connector負責偵聽一個TCP端口,接收相應的請求,並轉發給綁定的Engine處理。Engine處理完後,通過Connector把結果返回給客戶端。在配置了Executor的情況下,所有Connector的線程受Executor統一管理。

Tomcat 之圖文解析 Server.xml 配置

容器

Tomcat裏有四種層次的容器:Engine、Cluster、Host、Context,

從屬關係爲:

Context -> (Cluster in Host) -> Host -> (Cluster in Engine) -> Engine

具體關係如下圖所示:

Tomcat 之圖文解析 Server.xml 配置

Engine容器

Engine是Service的請求處理引擎,負責處理所有Connector發過來的請求,並將內部處理完畢的結果返回給Connector。它是最外層的容器。

★ Engine元素屬性

■ Engine.name - 引擎的名稱

默認配置定義了一個Engine,和外層的Service一樣,也叫Catalina。反正一個Service只有一個Engine,這麼起名問題也不大。

■ Engine.defaultHost - 默認採用哪一個子容器Host來處理請求

■ Engine.jvmRoute - 一個用於負載均衡場景下的唯一標識符

默認的負載均衡場景下,Tomcat採用一種被稱作粘性session的機制管理session信息。

粘性session就是將用戶“粘”在其中一個Engine上。比方說,客戶端剛訪問進來時被Nginx轉發到Engine#1並完成了登錄驗證,那麼接下來的每次請求都應該轉發到這個Engine。如果該機制失效,客戶端的後續訪問被Nginx轉發到Engine#2的話,由於Engine#2並沒有該客戶端的session信息,將會要求重新登錄。

爲了實現粘性session,Engine需要告訴Nginx,某一個session是我處理的,後續這個session都要發給我。方法就是給Engine定義一個唯一的jvmRoute,附在它受理的sessionID上,再返回給Nginx。例如,配置jvmRote="Engine#1"。

★ Engine上下文配置

每一個Engine都在安裝目錄的conf文件夾下有一個對應的二級目錄,例如默認的conf/cataline。相應的,Engine下的每一個Host,都會在Engine對應的二級目錄下有一個三級目錄,例如默認的conf/cataline/localhost。其路徑規則爲:

conf//

作用於整個Engine或整個Host的上下文信息可以配置在這些個目錄中。該目錄可以通過相應容器的xmlBase屬性進行修改。

Host 容器

一個Host就是一個虛擬主機,對應一個或多個域名。

★ Host元素屬性

■ Host.name - 主機名稱(域名)

默認配置定義了一個名爲 localhost 的主機。至少要有一個Host的名稱與Engine的defaultHost一致。

除了域名外,Host可以通過子節點alias來配置別名。別名的作用與域名一致。例如:

... a.com blog.a.com c.com ...

其作用機制如下圖所示:

Tomcat 之圖文解析 Server.xml 配置

■ Host.appBase - 虛擬主機的根目錄

該參數的默認值爲webapps。一般情況下,每一個 webapp 的 URL 和它所在的目錄名稱相同。以webapps目錄下的manager和docs兩個程序爲例(ROOT是個例外):

# 目錄名即路徑名

webapps/manager:http://localhost:8080/manager

webapps/docs:http://localhost:8080/docs

# 特例 - ROOT等於空字符串

webapps/ROOT:http://localhost:8080/

■ Host.unpackWARs - 放到 webapps 目錄下的 WAR-file 是否應該被解壓

如設爲false,Tomcat 將會直接從 *.war文件運行應用,但可能導致應用運行變慢。

■ Host.autoDeploy - 是否自動部署放到 webapps 目錄下的應用

Context 容器

Context代表Host下面的一個虛擬目錄。

在不配置Context的情況下是這樣的:

If HostName:my.oshina.net

-> HostUrl:http://my.oschina.net/

So Brower:http://my.oschina.net/mzdbxqh

-> 訪問:webapps/mzdbxqh

現在配置一個Context,同樣訪問博客域名,就變成了訪問"D:/mzdbxqh"

★ Context元素屬性

■ Context.docBase - 應用程序的路徑或者是WAR文件存放的路徑

■ Context.path - 此web應用程序的上下文路徑

配置後,Context的訪問url爲:http://localhost:8080/path/

path爲空的話,訪問url爲:http://localhost:8080/

■ Context.reloadable - 是否支持熱部署

如果爲true,則tomcat會自動檢測應用程序的/WEB-INF/lib 和/WEB-INF/classes目錄的變化,並通過類加載器重新加載class文件,以實現在不重啓tomcat的情況下重新部署。

因爲配置文件基本是在web程序啓動時一次性載入內存的,故一般來說Tomcat的熱部署對配置文件無效。另外,只有新創建實例時纔會向類加載器請求重新加載過的class,因此,Tomcat的熱部署對於使用Spring管理的單例也是無效的。這兩種情況需要web應用程序配合着寫熱部署的業務邏輯才能實現。

■ Context.crossContext - 不同context是否共享session

注意,這個跨應用共享session跟Cluster集羣是不一樣的。前者是指可以通過ServletContext.getContext()交叉訪問其他Context的session,後者默認配置下是採用服務器session複製的方式,將每一個節點的session變動複製到所有節點。

Cluster容器

Tomcat的Cluster是一個集羣容器。它的集羣策略是複製session,把集羣內一個容器的session變動通過廣播複製到其他所有容器上。Cluster可配置在Engine或Host內。

此外,複製session的模式因爲對網絡(廣播複製)和內存(每一個JVM實例都要保存所有在線用戶的session)的負擔較大,在大型分佈式場景下一般採用session共享的方式。具體可以瞭解一下Spring Session。以上三種session管理方式的對比如下圖所示:

Tomcat 之圖文解析 Server.xml 配置

Tomcat 之圖文解析 Server.xml 配置

Tomcat 之圖文解析 Server.xml 配置

其他

Connector組件

開頭說過,Connector就是牆上的插座,負責偵聽一個具體的TCP端口,並通過該端口處理Engine與客戶端之間的交互。默認配置定義了兩個 Connector:

更多Connector和Executor線程池的配置會在Tomcat性能調優的章節進行說明。

Valve組件

Valve的中文含義是閥門,可以簡單地理解爲Tomcat的攔截器。它負責在請求發送到應用之前攔截HTTP請求,可以定義在任何容器中。默認配置中定義了一個AccessLogValve,負責攔截HTTP請求,並寫入到日誌文件中。

prefix="localhost_access_log." suffix=".txt"

pattern="%h %l %u %t "%r" %s %b" />

Listener組件

Listener即監聽器,負責監聽服務器端的行爲。此處需要了解的監聽器有兩個:

Realm組件

Realm提供了一種用戶密碼與web應用的映射關係。tomcat自帶的manager管理工具就是根據conf/tomcat-users.xml中定義的賬號來實現登錄的。我們一般通過Shiro來實現,此處不作解釋。

GlobalNamingResources組件

全局命名資源(過JNDI實現,相當於一臺交換機,可以通過地址名訪問各種系統外部資源。例如,通過一個名稱,訪問預設置好的一個Mysql連接池)。默認定義了一個名稱爲UserDatabase的JNDI,通過“conf/tomcat-users.xml”得到了一個用於用戶授權的內存數據庫。我們一般通過Spring進行管理,此處不作解釋。

Tomcat 處理 Http 請求的過程

請求地址爲:http://my.oschina.net/mzdbxqh

● 請求通過DNS發送到指定主機的80端口,被負責偵聽80端口的HTTP/1.1 Connector攔截

● Connector把請求轉發給所在的Service的Engine,並等待Engine的迴應

● Engine獲得請求my.oschina.net/mzdbxqh,匹配它所擁有的所有虛擬主機Host

● Engine匹配到名爲my.oschina.net的Host

如果匹配不到就交給defaultHost

● 匹配的Host獲得請求/mzdbxqh,匹配它所擁有的所有Context

● Host匹配到path爲mzdbxqh的Context

►如果匹配不到就嘗試匹配Path爲""的Context

►如果還匹配不到就嘗試到appBase參數對應的目錄下找mzdbxqh文件夾

● 匹配的Context獲得請求/,匹配web.xml中配置的Servlet

如果匹配不到就嘗試匹配Welcome-file-list

● Context匹配到url-pattern爲"/"的servlet,對應於org.springframework.web.servlet.DispatcherServlet

● SpringMVC處理請求(後面章節再說),返回HttpServletResponse

● Context把HttpServletResponse對象返回給Host

● Host把HttpServletResponse對象返回給Engine

● Engine把HttpServletResponse對象返回給Connector

● Connector把HttpServletResponse對象返回給客戶端

相关文章