Apache Tomcat 是一款非常著名的開源 Servlet/JSP 容器。
原文:http://www.solol.org/technologic/java/j-tomcatarch/
Apache Tomcat 是一款非常著名的開源 Servlet/JSP 容器,被用做 Java Servlet 和 JavaServer Pages 技術的官方參考實現。如果您要了解這兩種技術的細節可以查閱參考資料。
讓我們先來瀏覽一下 Tomcat 體系結構中的六個主要概念:
由
于Tomcat體系結構的內容非常豐富,所以本文非常長。因此我們盡量的使每一部分盡可能自成一體,使您可以獨立閱讀。如果您不是想全面了解Tomcat
的體系結構,只是想解決某一部分的具體問題,那么我們建議您使用目錄導航到相關的內容,而不必在其它的內容上花費寶貴的時間。
Server代表整個容器(container)。它可以包含一個或多個Service,還可以包含一個GlobalNamingResources。
值
得注意的是在標準的Server接口中沒有包括Lifecycle接口,但是在標準實現
org.apache.catalina.core.StandardServer中卻實現了Lifecycle這個接口,這使得我們可以為Tomcat
的標準實現設置Listener。一般的方法是在conf/server.xml文件中加入:
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.solol.listener.XXXLifecycleListener" />
<Listener className="org.solol.listener.XXXLifecycleListener" />
:
:
:
</Server>
其中的XXXLifecycleListener為您自定義的LifecycleListener,而且必須要實現LifecycleListener接口。您可以在這里設置多個LifecycleListener,但要使用不同的名字。
由于在Tomcat的官方文檔中沒有顯著的說明,所以這種使用Listener的方式沒有體現在稍后給出的 體系結構圖 中。
Server支持className,port和shutdown三個公共屬性,而標準實現org.apache.catalina.core.StandardServer還可能支持一些擴展屬性。詳細的內容您可以查閱這里。
您可以通過稍后給出的 體系結構圖 了解在整個Tomcat體系結構中Server所處的位置。
Service中可以含有一個或多個Connector,但只能含有一個Engine。這使得不同的Connector可以共享同一個Engine。同一個Server中的多個Service之間沒有相關性。
值
得注意的是在標準的Service接口中沒有包括Lifecycle接口,但是在標準實現
org.apache.catalina.core.StandardService中卻實現了Lifecycle這個接口,這使得我們可以為
Tomcat的標準實現設置Listener。
由于在Tomcat的官方文檔中沒有顯著的說明,所以這種使用Listener的方式沒有體現在稍后給出的 體系結構圖 中。
Service支持className和name兩個公共屬性,而標準實現org.apache.catalina.core.StandardService還可能支持一些擴展屬性。詳細的內容您可以查閱這里。
您可以通過稍后給出的 體系結構圖 了解在整個Tomcat體系結構中Service所處的位置。
Engine負責接收和處理來自它所屬的Service中的所有Connector的請求。
Engine
支持backgroundProcessorDelay、className、defaultHost、jvmRoute和name五個公共屬性,而標準
實現org.apache.catalina.core.StandardEngine還可能支持一些擴展屬性。詳細的內容您可以查閱這里。
您可以通過稍后給出的 體系結構圖 了解在整個Tomcat體系結構中Engine所處的位置。
從圖中可以看出Engine右邊有四個不同顏色的小方塊,它們表示Engine所支持的四個不同的特性。相同顏色的小方塊可能也會出現在其它的地方,這表示在那里也支持相同的或相似的特性。每種特性的具體描述可以在文中的Special Features中找到。
從圖中可以看出Engine下邊有一個紅色的圓角矩形,它們表示Engine所支持的一個內嵌組件。相同顏色的圓角矩形可能也會出現在其它的地方,這表示在那里也支持相同的或相似的內嵌組件。每種內嵌組件的具體描述可以在文中的Nested Components中找到。
Host表示一個虛擬主機,并和一個服務器的網絡名關聯。注意Engine中必須有一個Host的名字和Engine的defaultHost屬性匹配。
有時候,網絡管理員可能希望將多個網絡名關聯到一個虛擬主機,這可以通過下文介紹的Host Name Aliases特性完成。
Host
支持appBase、autoDeploy、backgroundProcessorDelay、className、deployOnStartup和
name六個公共屬性,而標準實現org.apache.catalina.core.StandardHost還可能支持一些擴展屬性。詳細的內容您可
以查閱這里。
您可以通過稍后給出的 體系結構圖 了解在整個Tomcat體系結構中Host所處的位置。
從圖中可以看出Host右邊有八個不同顏色的小方塊,它們表示Host所支持的八個不同的特性。相同顏色的小方塊可能也會出現在其它的地方,這表示在那里也支持相同的或相似的特性。每種特性的具體描述可以在文中的Special Features中找到。
從圖中可以看出Host下邊有一個紅色的圓角矩形,它們表示Host所支持的一個內嵌組件。相同顏色的圓角矩形可能也會出現在其它的地方,這表示在那里也支持相同的或相似的內嵌組件。每種內嵌組件的具體描述可以在文中的Nested Components中找到。
Connector負責接收來自客戶端(Client)的請求。比較常見的兩個是HTTP Connector和AJP Connector。
您可以通過稍后給出的 體系結構圖 了解在整個Tomcat體系結構中Connector所處的位置。
Context表示在虛擬主機中運行的web應用程序。一個虛擬主機中能夠運行多個Context,它們通過各自的Context Path進行相互區分。如果Context Path為"",那么該web應用為該虛擬主機的默認的web應用。
目前可以通過四種方式將Context加入Host:
- $CATALINA_HOME/conf/context.xml,其中Context元素中的信息會被所有web應用程序加載
- $CATALINA_HOME/conf/[enginename]/[hostname]/context.xml.default,其中Context元素中的信息會被hostname主機下的所有web應用程序加載
- $CATALINA_HOME/conf/[enginename]/[hostname]/目錄中所有以.xml為擴展名的文件,其中Context元素中的信息會被hostname主機下的所有web應用程序加載
- 如果通過上面的步驟沒有找到,那么最后要從web應用程序的/META-INF/context.xml目錄中查找
Context
支持backgroundProcessorDelay、className、cookies、crossContext、docBase、
override、privileged、path、reloadable和wrapperClass十個公共屬性,而標準實現
org.apache.catalina.core.StandardContext還可能支持一些擴展屬性。詳細的內容您可以查閱這里。
您可以通過稍后給出的 體系結構圖 了解在整個Tomcat體系結構中Context所處的位置。
從圖中可以看出Context右邊有十個不同顏色的小方塊,它們表示Context所支持的十個不同的特性。相同顏色的小方塊可能也會出現在其它的地方,這表示在那里也支持相同的或相似的特性。每種特性的具體描述可以在文中的Special Features中找到。
從
圖中可以看出Context下邊有五個不同顏色的圓角矩形,它們表示Context所支持的五個內嵌組件。相同顏色的圓角矩形可能也會出現在其它的地方,
這表示在那里也支持相同的或相似的內嵌組件。每種內嵌組件的具體描述可以在文中的Nested Components中找到。
Tomcat 的體系結構圖

GlobalNamingResources 組件為 Server 定義全局 JNDI 資源。這些資源出現在 Server 的全局 JNDI 資源上下文中。這個上下文和每個 web 應用程序的 JNDI 上下文不同。在全局 JNDI 上下文中定義的資源在每個
web 應用程序的 JNDI 上下文中不可見,但是可以通過 Resource Links 來改變這種可見性。如果您要了解在 Tomcat 中如何使用 JNDI 資源可以查閱參考資料。
從前面給出的 體系結構圖
中可以看出GlobalNamingResources右邊有四個不同顏色的小方塊,它們表示GlobalNamingResources所支持的四個不
同的特性。相同顏色的小方塊可能也會出現在其它的地方,這表示在那里也支持相同的或相似的特性。每種特性的具體描述可以在文中的Special
Features中找到。
從前面給出的 體系結構圖 中可以看出,Realm組件在Engine、Host和Context中都有支持。
Realm
是一個"數據庫"存儲著用戶名、密碼和角色信息。通過自定義Realm可以將Catalina集成到其它的環境。Engine、Host和Context
中的Realm可以被較低級別的容器繼承,即Host繼承Engine的Realm,Context繼承Host的Realm,除非我們顯示的禁止這種繼
承。
Realm支持className一個公共屬性。Tomcat提供了多個實現:
- org.apache.catalina.realm.JDBCRealm
- org.apache.catalina.realm.DataSourceRealm
- org.apache.catalina.realm.JNDIRealm
- org.apache.catalina.realm.MemoryRealm
如果您要了解這些Realm的更多信息,可以查閱這里。
如果您要了解這些Realm的更多的設置信息,可以查閱參考資料。
從前面給出的 體系結構圖 中可以看出,Loader組件只在Context中都有支持。
Loader是web應用程序的類裝載器。必須有一個類裝載器按照Servlet Specification的要求從如下的位置裝載類:
- 從web應用程序的/WEB-INF/classes目錄裝載
- 從web應用程序的/WEB-INF/lib目錄中的jar文件中裝載
- 從Catalina中裝載對于所有web應用可見的資源
Loader元素應該嵌入到Context元素中,如果沒有設置那么會自動創建一個默認的Loader。如果想更深入的了解Catalina實現的Loader可以查閱參考資料。
Loader支持className、delegate和reloadable三個公共屬性,而標準實現org.apache.catalina.loader.WebappLoader還可能支持一些擴展屬性。詳細的內容您可以查閱這里。
從前面給出的 體系結構圖 中可以看出,Manager組件只在Context中有支持。
Manager是session管理器(session manager),負責session的創建和維護。
Manager元素應該嵌入到Context元素中,如果沒有設置那么會自動創建一個默認的Manager。
Manager
支持className和distributable兩個公共屬性,而標準實現
org.apache.catalina.session.StandardManager和
org.apache.catalina.session.PersistentManager還可能支持一些擴展屬性。詳細的內容您可以查閱這里。
從前面給出的 體系結構圖 中可以看出,Resources組件只在Context中有支持。
Resources表示web應用程序的靜態資源。這使得我們有可能實現non-filesystem based Resources。如果想更深入的了解可以查閱參考資料
Resources元素應該嵌入到Context元素中,如果沒有設置那么會自動創建一個默認的基于文件系統的Resources。
Resources支持className一個公共屬性,而標準實現org.apache.naming.resources.FileDirContext還可能支持一些擴展屬性。詳細的內容您可以查閱這里。
從前面給出的 體系結構圖 中可以看出,WatchedResource組件只在Context中都有支持。
WatchedResource用來告知Auto Deployer那些靜態資源的更新需要被監控。如果被監控的資源被更新了那么該資源所對應的web應用將會被重新裝載。這個元素的內容必須是一個String。
從前面給出的 體系結構圖 中可以看出,Logging特性在Engine、Host和Context中都有支持。這個特性使得我們可以區分日志記錄的具體來源。
在Engine、Host和Context中的日志類別分別為:
org.apache.catalina.core.ContainerBase.[enginename]
org.apache.catalina.core.ContainerBase.[enginename].[hostname]
org.apache.catalina.core.ContainerBase.[enginename].[hostname].[path]
其中中括號([])中為具體的名稱。
Logging特性的實現是通過org.apache.catalina.core.ContainerBase來完成的。
從前面給出的 體系結構圖 中可以看出,Access Logs特性在Engine、Host和Context中都有支持。
- Engine中的Access Logs記錄所有Engine處理的請求的訪問日志
- Host中的Access Logs記錄所有Host處理的請求的訪問日志
- Context中的Access Logs記錄所有Context處理的請求的訪問日志
一般的配置方法是在conf/server.xml文件的相關元素中加入:
<Engine ...>
...
<Valve className="org.apache.catalina.valves.AccessLogValve"
prefix="catalina_access_log." suffix=".txt" pattern="common"/>
...
</Engine>
上面的<Engine>,在Host中要被換成<Host>,在Context中要被換成<Context>。
Access Logs特性的實現是通過Tomcat的Value框架來完成的。如果您要了解這種技術的細節可以查閱參考資料。
如果您要了解Access Log Valve設置的更多信息,可以查閱這里。
從前面給出的 體系結構圖 中可以看出,Lifecycle Listeners特性在Engine、Host和Context中都有支持。這個特性使得我們可以方便的進行生命周期的管理。
值得一提的是在Tomcat的標準實現中Server和Service也支持生命周期的管理,但是在官方文檔中沒有顯著的說明,所以沒有在圖中體現出來。細節可以查閱Server和Service部分。
- Engine中的Lifecycle Listeners監聽該Engine的生命周期事件(Eifecycle Event)
- Host中的Lifecycle Listeners監聽該Host的生命周期事件(Eifecycle Event)
- Context中的Lifecycle Listeners監聽該Context的生命周期事件(Eifecycle Event)
一般的配置方法是在conf/server.xml文件的相關元素中加入:
<Engine ...>
...
<Listener className="com.mycompany.mypackage.MyListener" ... >
...
</Engine>
上面的<Engine>,在Host中要被換成<Host>,在Context中要被換成<Context>。
另外,可以通過<Listener>元素為listener添加屬性。
注意和Container Event區別。
從前面給出的 體系結構圖 中可以看出,Request Filters特性在Engine、Host和Context中都有支持。
- Engine中的Request Filters過濾所有Engine處理的請求
- Host中的Request Filters過濾所有Host處理的請求
- Context中的Request Filters過濾所有Context處理的請求
一般的配置方法是在conf/server.xml文件的相關元素中加入:
<Engine ...>
...
<Valve className="org.apache.catalina.valves.RemoteHostValve"
allow="*.mycompany.com,www.yourcompany.com"/>
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
deny="192.168.1.*"/>
...
</Engine/>
上面的<Engine>,在Host中要被換成<Host>,在Context中要被換成<Context>。
Request Filters特性的實現是通過Tomcat的Value框架來完成的。如果您要了解這種技術的細節可以查閱參考資料。
如果您要了解Remote Address Filter設置的更多信息,可以查閱這里。
如果您要了解Remote Host Filter設置的更多信息,可以查閱這里。
從前面給出的 體系結構圖 中可以看出,Automatic Application Deployment特性只在Host中都有支持。
如果使用Host的標準實現,同時deployOnStartup屬性值為true(這是默認值),那么Catalina在首次啟動時會自動完成下面的工作:
- $CATALINA_HOME/conf/[engine_name]/[host_name]目錄下的所有XML文件都被假定含有<Context>元素。
- appBase
目錄下的所有沒有展開的war文件(沒有展開的意思是沒有和war文件名不包括.war擴展名對應的目錄存在)會被自動展開,除非unpackWARs屬
性值為false。如果重新部署更新的war文件,在重起Tomcat之前要刪除先前展開的目錄(如果autoDeploy屬性值為true那么只要刪除
先前展開的目錄更新后的war文件就會自動展開)。
- 對
于appBase中含有/WEB-INF/web.xml文件的任何子目錄都會自動產生一個Context,不管該子目錄是否在conf
/server.xml文件中出現過。這個新產生的Context將會根據DefaultContext的屬性值進行設置,其context
path為“/目錄名”。如果目錄名為ROOT,那么context path為“”。
因此要使用上面的規則需要將XML設置文件拷貝到$CATALINA_HOME/conf/[engine_name]/[host_name]目錄下或將war文件和含有web應用的目錄拷貝到appBase目錄下。
自動部署(Auto Deployer)也會跟蹤如下web應用程序的變化:
- 更新WEB-INF/web.xml文件將會使web應用程序重新加載
- 更新已展開的war文件會使web應用程序卸載(undeploy)(同時移除先前展開的目錄)并重新部署(deployment)
- 更新XML設置文件會使web應用程序卸載(undeploy)(不移除任何展開的目錄)并重新部署(deployment)
在使用自動部署的時候XML設置文件中的docBase要指向appBase目錄之外。否則部署將很困難或應用程序會被部署兩次。
如果要顯示的定義context,那么需要關閉自動部署。否則相應的context將會部署兩次,這可能會有問題。
從前面給出的 體系結構圖 中可以看出,Host Name Aliases特性只在Host中都有支持。
在一些時候,網絡管理員會將多個網絡名(在DNS服務器中)解析到同一個服務器。通常每一個網絡名會對應到一個Host。不過有時候需要將多個網絡名對應到一個Host,Host Name Aliases用來完成這個目標。
一般的配置方法是在conf/server.xml文件的相關元素中加入:
<Host name="www.mycompany.com" ...>
...
<Alias>mycompany.com</Alias>
...
</Host>
<Host>元素中可以嵌入一個或多個<Alias>元素。
從前面給出的 體系結構圖 中可以看出,Single Sign On特性只在Host中都有支持。
在一些時候,特別是在Portal環境下,可能會希望當用戶訪問一個虛擬主機下的多個web應用時只登陸一次,即所謂的單點登陸。
一般的配置方法是在conf/server.xml文件的相關元素中加入:
<Host name="localhost" ...>
...
<Valve className="org.apache.catalina.authenticator.SingleSignOn"
debug="0"/>
...
</Host>
Single Sign On操作遵循下面的規則:
- 該虛擬主機下的所有Web應用程序必須共享同一個Realm。在實踐中通常通過為Host或(對應的Engine)嵌入Realm而不是為每一個Context嵌入相同的Realm來實現。
- 在用戶訪問該虛擬主機下的所有Web應用程序中的非保護資源時不需要驗證。
- 在用戶訪問該虛擬主機下的所有Web應用程序中的保護資源時需要驗證。
- 一旦被驗證,就會對該虛擬主機下的所有Web應用程序有效,而不用每個應用程序單獨驗證。
- 如果用戶從一個Web應用中退出,那么所有Web應用程序中的session都會失效。
- 使用SSO需要客戶環境支持cookies。
Single Sign On特性的實現是通過Tomcat的Value框架來完成的。如果您要了解這種技術的細節可以查閱參考資料。
如果您要了解Single Sign On設置的更多信息,可以查閱這里。
從前面給出的 體系結構圖 中可以看出,User Web Applications特性只在Host中都有支持。
許多Web服務器都可以處理如下形式的請求:
http://www.mycompany.com:8080/~craigmcc
其中craigmcc為系統的一位用戶名。具體的處理過程和操作系統相關。
在類Unix或Linux等操作系統下配置方法如下:
<Host name="localhost" ...>
...
<Listener className="org.apache.catalina.startup.UserConfig"
directoryName="public_html"
userClass="org.apache.catalina.startup.PasswdUserDatabase"/>
...
</Host>
在Windows等操作系統下配置方法如下:
<Host name="localhost" ...>
...
<Listener className="org.apache.catalina.startup.UserConfig"
directoryName="public_html"
homeBase="c:\Homes"
userClass="org.apache.catalina.startup.HomesUserDatabase"/>
...
</Host>
這兩種配置最主要的區別就是發現用戶和為用戶匹配路徑。PasswdUserDatabase依據/etc/passwd發現用戶而HomesUserDatabase依據homeBase="c:\Homes"發現用戶。
User Web Applications是通過Listener(org.apache.catalina.startup.UserConfig)的方式實現的。即在Host啟動時該Listener會被執行,它會為每一個發現的用戶構建對應Context。
使用User Web Applications時需要考慮以下的一些問題:
- 依據DefaultContext來設置為每一個用戶建立Context
- 可以使用多個Listener元素(在這么做之前您最好查閱一下UserConfig)
- 用戶所對應的目錄應該具有讀寫權限
從前面給出的 體系結構圖 中可以看出,Automatic Context Configuration特性只在Context中都有支持。
如果使用標準的Context實現,當Catalina啟動或Web應用裝載時,會按如下的步驟自動進行設置:
- 如果沒有指定Loader元素,那么一個標準的Loader將會被設置
- 如果沒有指定Manager元素,那么一個標準的Manager將會被設置
- 如果沒有指定Resources元素,那么一個標準的Resources將會被設置
- 處理conf/web.xml文件
- 處理/WEB-INF/web.xml文件
- 如果設置了security constraints,那么一個對應的Authenticator會被創建
從前面給出的 體系結構圖 中可以看出,Context Parameters特性只在Context中有支持。
如下的兩種配置等價,都是為Web配置初始參數:
<Context ...>
...
<Parameter name="companyName" value="My Company, Incorporated" override="false"/>
...
</Context>
<context-param>
<param-name>companyName</param-name>
<param-value>My Company, Incorporated</param-value>
</context-param>
從前面給出的 體系結構圖 中可以看出,Environment Entries特性在GlobalNamingResources和Context中都有支持。
如下的兩種配置等價,都是為配置environment entry resources:
<GlobalNamingResources ...>
...
<Environment name="maxExemptions" value="10" type="java.lang.Integer" override="false"/>
...
</GlobalNamingResources>
<env-entry>
<env-entry-name>maxExemptions</param-name>
<env-entry-value>10</env-entry-value>
<env-entry-type>java.lang.Integer</env-entry-type>
</env-entry>
這里使用GlobalNamingResources表示environment entry resources對于所有Web應用程序可見。如果換成Context則表示只對相應Web應用程序可見。
從前面給出的 體系結構圖 中可以看出,Resource Definitions特性在GlobalNamingResources和Context中都有支持。
如下的兩種配置等價,都是為定義Resource:
<GlobalNamingResources ...>
...
<Resource name="jdbc/EmployeeDB" auth="Container" type="javax.sql.DataSource"
description="Employees Database for HR Applications"/>
...
</GlobalNamingResources>
<resource-ref>
<description>Employees Database for HR Applications</description>
<res-ref-name>jdbc/EmployeeDB</res-ref-name>
<res-ref-type>javax.sql.DataSource</res-ref-type>
<res-auth>Container</res-auth>
</resource-ref>
這里使用GlobalNamingResources表示Resource對于所有Web應用程序可見。如果換成Context則表示只對相應Web應用程序可見。
從前面給出的 體系結構圖 中可以看出,Resource Links特性在GlobalNamingResources和Context中都有支持。
ResourceLink
元素用來將資源從全局上下文(global context)中連接到每個Web應用的上下文(per-web-application
contexts)中。使用方式依據GlobalNamingResources和Context的不同分成兩種:
<DefaultContext>
<ResourceLink name="bean/MyBeanFactory" global="bean/MyBeanFactory" type="com.mycompany.MyBean"/>
</DefaultContext>
<Context ...>
...
<ResourceLink name="linkToGlobalResource" global="simpleValue" type="java.lang.Integer"/>
...
</Context>
從前面給出的 體系結構圖 中可以看出,Transaction特性在GlobalNamingResources和Context中都有支持。
通過在JNDI中查詢java:comp/UserTransaction
可以得到UserTransaction的引用。
新浪微博:http://t.sina.com.cn/androidguy 昵稱:李寧_Lining