本文分為三部分,分别為:
tomcat檔案系統
tomcat的主要組成部分
tomcat各組成部分之間的關系以及它們如何協作,構成一個系統
tocmat6的結構與之前的結構有很大不同,檔案目錄都不一樣。我個人感覺與之前的版本相比,tomcat6的結構更清晰簡潔,也更容易了解一些。改變的原因據說所為了解決一些由檔案系統結構帶來的問題,詳細的内容我也不清楚。不過由此可以看出,系統的目錄結構一定要認真設計,因為以後更改起來會很麻煩,可能會造成一些相容性的問題。
下面這張圖就算tomcat的目錄結構:
catalina_home指的是tomcat的安裝目錄,如c:/program files/apache tomcat group/tomcat6.0
bin目錄:這個目錄裡檔案的主要作用所控制tomcat的啟動與關閉(使用catalina或startup腳本),以及與啟動關閉有關的安全管理(uli)等。archive版(解壓縮後直接用的那種)的比使用安裝包安裝的那種要多一些sh和bat腳本。startup腳本實質上也是在調用catalina腳本,隻不過所讓它在背景運作。這裡面也有一些jar包,包括bootstrap.jar, commons-daemon.jar, tomcat-juli.jar。還包括一些exe檔案,是用來在windows平台安裝服務用的。
conf目錄:這個目錄所我們與tomcat打交道最多的一個目錄。裡面主要所配置檔案,當tomcat啟動時,就按照這裡面的配置建立一些對象(組成worker,我認為)。裡面的檔案及簡單描述如下:
catalina.policy:包含java security manager使用的安全政策描述。它替代了java自身所帶的java.policy檔案。這個檔案的主要作用是防止jsp代碼等使用者代碼破壞tomcat容器,如system.exit(0)。隻用在使用指令行啟動tomcat并使用-security參數時,這個檔案才被使用。
catalina.properties:裡面包含了不能被jsp或servlet修改的jar檔案清單,如java.* org和tomcat.apache.*等。
context.xml:顧名思義,這是有關context的配置檔案。由于這個context.xml位于頂層,是以是一個被所有web應用程式使用的配置檔案。預設内容為web.xml檔案的位置。
logging.properties:預設為juli logger使用的配置檔案。
server.xml:tomcat中最主要的配置檔案,定義了tomcat的體系結構。這個檔案是被digester用來在tomcat啟動時建構tomcat容器的配置檔案。
tocmat-users.xml:有關tocmat管理者身份的配置檔案,它是同server.xml中的userdatabase realm一起使用的。
web.xml:這個預設的web.xml被tomcat下所有的應用程式所使用。主要包括<servlet-mapping>, <servlet>标簽,<mime-type>标簽和<welcome-file-list>标簽。
自動生成的使用者應用程式的配置檔案。當使用者在tomcat中部署一個應用時,tomcat會自動在這個檔案夾裡生成一個與應用程式中的contex.xml等價的檔案。這個檔案一般所放在一個目錄中,目錄結構如下:[servlet引擎名(catalina)]/[host name(localhost)]/[context path name(petstore)].xml。此外,使用者還可以建立一個[servlet 引擎名]/[主機名]/context.xml.default來建立某個引擎-主機組合下的預設配置檔案。
lib目錄:裡面包含了tomcat容器使用的所有jar包。這裡也是使用者存放多個web應用程式共享的jar包以及jdbc連接配接包的地方。
log目錄:裡面包含有tomcat生成的日志檔案。這些日志檔案預設是由juli生成的,日志檔案是按天為機關生成的。
temp目錄:顧名思義,這個檔案夾所tomcat用來存放臨時檔案用的。
webapps目錄:這是預設的web應用程式存放的位置。如果将war包放到這個目錄下,tomcat會自動将這個war包解壓;如果這個war檔案被删除,解壓後生成的檔案夾也會被自動删除。
work目錄:工作目錄。這裡是tomcat将jsp檔案轉換為java servlet的地方,裡面檔案的目錄結構一般所這樣的:[引擎名]/[主機名]/web應用程式
從上面這些目錄結構可以猜想的到,servlet引擎是tomcat與web應用程式的一個重要界限,也算tomcat的核心所在。
在tocmat4以後,tomcat的體系機構發生了很大的變化。tomcat4以後的版本沒有再基于以前的版本進行改進,而是徹底的重寫。下面這張tomcat示意圖比較好地反映了一個經典的tomcat6的體系結構。值得注意的是,這張圖裡的有些部分并不是tomcat必須的。例如,在有其他的web server(如apache http server)來實作解譯使用者request并傳給web應用程式的時候,engine和host可以被其他的web server替代。
在上面這張圖中,有些元件隻能有一個,使用灰色背景表示,在這張圖裡有server,engine和context;有些可以有多個,使用白色背景表示,此圖中有service, connector, logger, valve, realm, host, wapper。
the server就是tomcat自身,一個tomcat程式執行個體(instance)。它的一個重要屬性就是關閉tomcat的端口号。“在一個給定的jvm中,隻能建立一個tomcat執行個體。“這句話是我從《apache tomcat6》這本書中看到的,但不是很了解。目前我的了解是這樣,
the server對象是server接口的一個實作,一般常用的是standardserver類的一個對象。
一個server可以有多個service,一般一個server隻有一個service。一個service包括一個engine和多個connector。
an engine is a request-processing component that represents the catalina servlet engine. it examines
the http headers to determine the virtual host or context to which requests should be passed.
上面這段話翻譯過來大概是這樣:
一個引擎是一個處理請求的元件,也就是catalina servlet引擎。它通過http request請求頭的資訊來向相應的virtual host或context轉發request。
由此可見,這裡的engine是一個概念,而不是某個具體的檔案,凡是符合一定标準的元件都可以作為引擎。
每一個service都是由一組connector(處理伺服器與用戶端之間互動的元件)與一個引擎組成的。引擎的作用是接受connector傳過來的request并将他們轉發給相應的host。
tomcat中的service一般是實作了service接口的一個standardservice類的對象。
connector是使用者請求到達伺服器的第一站。每個connector都有一個端口号,常用的connector有兩種,一種是http connector,另一種是ajp connector,除此之外,還有一些其他類型的接口。如果要使用ssl,在配置檔案裡修改的也是connector屬性。
我覺得這是tomcat中最重要的部分,雖然它并不是不可或缺的。engine除了前面所說的處理并轉發request功能外,還可以提供java servlet服務。正是engine實作了jsp到java檔案的轉換。
engine中的realm負責使用者驗證和授權。在一個web應用程式中,管理者會建立一些有不同權限的roles,實作這個機制的正是realm。realm可以管理的檔案包括文本檔案,資料庫表格,ldap 伺服器等。
在不同的級别上都可以設定realm,如engine中的realm就是頂層容器級的realm,而各個host,context也可以有自己的realm。
valve是用來預處理使用者請求的,有些類似于servlet中的filter。
顧名思義,logger是用來生成日志檔案的。engine級别的logger 适用于全局,除非被某個host或context級别的logger所覆寫。
host在功能上與apache中的 virtual host類似,在apache中virtual host用來實作在一台機器上安裝多個apache server,用他們的ip位址或主機名來區分。在tomcat中,多個host是通過主機名來區分的,如www.examle.com與www.example.net就可以被區分。
host是engine的一個成員,在一個engine中,可以有1個或多個host,包括一個預設的host和0個或多個虛拟的host。當engine無法确定将請求發給哪一個host時,就會将這個請求發給預設的那個host。
每個context對應一個web應用程式,一個web應用程式的配置包括通知engine/host web應用程式的位置(root folder,還可以設定是否在發生改變時是否自動重載。不過自動重載會降低系統性能,是以建議僅在調試時使用這個選項。
還可以在conetxt中設定errorpage,友善管理者檢查錯誤。預設情況下context是實作context接口的一個standard類的context對象。
在啟動時還可以設定context的參數,增加使用者驗證。每個context也是一個容器,裡面可以有0個或多個servlet,context将其作為standardwrapper對象加載進來。
tomcat中還定義了幾個分别表示request,response和session的類,這幾個類用來模拟用戶端和伺服器。
connector一般可以分為兩類,一類是http connector,另一類是ajp connector。connector主要由兩部分來實作,一部分在apache端,一般是一個c寫成的apache子產品,目前使用比較多的有mod_jk和mod_proxy兩種。另一部分在tomcat端,是用java寫成的。org.apache.catalina.connector類。這個類的構造函數接受一個參數,這個參數有兩種選擇,一個為http/1.1,另一個是ajp/1.3。
tomcat使用的一種“插件式(plugable)”的結構,管理這些插件的生命周期(何時啟動與關閉)。當使用者啟動tomcat時,tomcat中的那些插件也會一起啟動,當關閉時也是同樣。這種多米諾效應是通過lifecycle接口:lifecycleevent和lifecyclelistener 實作的。下面是lifecycle接口的代碼:
public interface lifecycle {
public static final string init_event = “init”;
public static final string start_event = “start”;
public static final string before_start_event = “before_start”;
public static final string after_start_event = “after_start”;
public static final string stop_event = “stop”;
public static final string before_stop_event = “before_stop”;
public static final string after_stop_event = “after_stop”;
public static final string destroy_event = “destroy”;
public static final string periodic_event = “periodic”;
public void addlifecyclelistener(lifecyclelistener listener);
public lifecyclelistener[] findlifecyclelisteners();
public void removelifecyclelistener(lifecyclelistener listener);
public void start() throws lifecycleexception;
public void stop() throws lifecycleexception;
}
幾乎所有的tomcat元件都實作了lifecycle接口,主要的控制元件都有lifecyclesuport對象,它們使用這個對象來管理其中的所有子lifecycle對象。使用lifecyclesupport對象,當頂層對象調用start()方法時,它就會調用它的子元件的start()方法,子元件的子元件又會調用start()方法,就這樣形成了多米諾效應。關閉時亦然。
lifecyclelistener接口可以被添加到任何層次的tomcat容器 (server, service, engine, host, or context),在server這個級别,預設的listener有三個。使用者可以定義自己的listener,不過需要将其在server.xml或context.xml中添加配置。使用者自定義的listener需要繼承lifecyclelistene接口。下面是lifecyclelistner的代碼和一個使用者自定義listener的一個示例:
public interface lifecyclelistener {
public void lifecycleevent(lifecycleevent event);
}
lifecycleevent()接收一個lifecycleevent類型的對象,這個對象包含事件類型和其他的附加資訊。下面是一個示例:
public mylistener implements lifecyclelistener {
public void lifecycleevent(lifecycleevent event){
if (lifecycle.start_event.equals(event.gettype())){
//code here to email that a start event was received
}
if (lifecycle.stop_event.equals(event.gettype())){
//code here to email that a stop event was received
}
在tomcat中處于核心地位的檔案應該就是這個了。當tomcat啟動時,apache commons digester就會讀取這份配置檔案。digester是用來讀取xml檔案并根據檔案來生成java對象的一種對象。
<server port=”8005” shutdown=”shutdown”>
<listener classname=”org.apache.catalina.core.aprlifecyclelistener”
sslengine=”on” />
<listener classname=”org.apache.catalina.core.jasperlistener” />
<listener classname=”org.apache.catalina.mbeans.serverlifecyclelistener” />
<listener classname=”org.apache.catalina.mbeans.
globalresourceslifecyclelistener” />
<service name=”catalina”>
<connector port=”8080” protocol=”http/1.1”
maxthreads=”150” connectiontimeout=”20000”
redirectport=”8443” />
<connector port=”8009” protocol=”ajp/1.3” redirectport=”8443” />
<engine name=”catalina” defaulthost=”localhost”>
<realm classname=”org.apache.catalina.realm.userdatabaserealm”
resourcename=”userdatabase”/>
<host name=”localhost” appbase=”webapps”
unpackwars=”true” autodeploy=”true”
xmlvalidation=”false” xmlnamespaceaware=”false”/>
</engine>
</service>
</server>
xml結構的本質是嵌套式的機構,tomcat的開發者們決定使tomcat自身也按這種結構設計。從這份示例server.xml文檔也可以看出,tomcat的結構和xml的結構是多麼的一緻。是以,要想弄清楚tomcat的結構,最快捷的方法就是閱讀配置檔案。(server.xml&context.xml)。