1. 程式人生 > >沉澱再出發:Tomcat的實現原理

沉澱再出發:Tomcat的實現原理

沉澱再出發:Tomcat的實現原理

一、前言

    在我們接觸java之後,相信大家都編寫過伺服器程式,這個時候就需要用到Tomcat了。Tomcat 伺服器是一個開源的輕量級Web應用伺服器,在中小型系統和併發量小的場合下被普遍使用,是開發和除錯Servlet、JSP 程式的首選。

二、Tomcat的基本原理

 2.1、Tomcat的架構

   Tomcat主要元件:伺服器Server,服務Service,聯結器Connector、容器Container。
   聯結器Connector和容器Container是Tomcat的核心。

   Tomcat 還有其它重要的元件,如安全元件 security、logger 日誌元件、session、mbeans、naming 等其它元件。這些元件共同為 Connector 和 Container 提供必要的服務。
   一個Container容器和一個或多個Connector組合在一起,加上其他一些支援的元件共同組成一個Service服務,有了Service服務便可以對外提供能力了,但是Service服務的生存需要一個環境,這個環境便是Server,Server元件為Service服務的正常使用提供了生存環境,Server元件可以同時管理一個或多個Service服務。

 2.2、Connector

    一個Connecter將在某個指定的埠上偵聽客戶請求,接收瀏覽器的發過來的 tcp 連線請求,建立一個 Request 和 Response 物件分別用於和請求端交換資料,然後會產生一個執行緒來處理這個請求並把產生的 Request 和 Response 物件傳給處理Engine(Container中的一部分),從Engine出獲得響應並返回客戶。 Tomcat中有兩個經典的Connector,一個直接偵聽來自Browser的HTTP請求,另外一個來自其他的WebServer請求。HTTP/1.1 Connector在埠8080處偵聽來自客戶Browser的HTTP請求,AJP/1.3 Connector在埠8009處偵聽其他Web Server(其他的HTTP伺服器)的Servlet/JSP請求。 Connector 最重要的功能就是接收連線請求然後分配執行緒讓 Container 來處理這個請求,所以這必然是多執行緒的,多執行緒的處理是 Connector 設計的核心。

 2.3、Container容器

    Container是容器的父介面該容器的設計用的是典型的責任鏈的設計模式,它由四個自容器元件構成,分別是Engine、Host、Context、Wrapper。這四個元件是負責關係,存在包含關係。通常一個Servlet class對應一個Wrapper,如果有多個Servlet定義多個Wrapper,如果有多個Wrapper就要定義一個更高的Container,如Context。 Context 還可以定義在父容器 Host 中,一個Host可以對應多個Context,Host 不是必須的,但是要執行 war 程式,就必須要 Host,因為 war 中必有 web.xml 檔案,這個檔案的解析就需要 Host 了,如果要有多個 Host 就要定義一個 top 容器 Engine 了。而 Engine 沒有父容器了,一個 Engine 代表一個完整的 Servlet 引擎。


    Engine 容器比較簡單,它只定義了一些基本的關聯關係。
    Host 容器是Engine 的子容器,一個Host在 Engine 中代表一個虛擬主機,這個虛擬主機的作用就是執行多個應用,它負責安裝和展開這些應用,並且標識這個應用以便能夠區分它們。它的子容器通常是 Context,它除了關聯子容器外,還有就是儲存一個主機應該有的資訊
    Context 容器代表 Servlet 的 Context,它具備了 Servlet 執行的基本環境,理論上只要有 Context 就能執行 Servlet 了。簡單的 Tomcat 可以沒有 Engine 和 Host。Context 最重要的功能就是管理它裡面的 Servlet 例項,Servlet 例項在 Context 中是以 Wrapper 出現的,還有一點就是 Context 如何找到正確的 Servlet 來執行它呢,Tomcat5 以前是通過一個 Mapper 類來管理的,Tomcat5 以後這個功能被移到了 request 中。
    Wrapper容器代表一個 Servlet,負責管理一個Servlet,包括的 Servlet 的裝載、初始化、執行以及資源回收。Wrapper是最底層的容器,它沒有子容器,所以呼叫它的addChild 將會報錯。
    Wrapper 的實現類是StandardWrapper,StandardWrapper還實現了擁有一個Servlet 初始化資訊的 ServletConfig,由此看出 StandardWrapper將直接和 Servlet 的各種資訊打交道。

2.4、HTTP請求過程

    Tomcat Server處理一個HTTP請求的過程:

 1 使用者點選網頁內容,請求被髮送到本機埠8080,被在那裡監聽的Coyote HTTP/1.1 Connector獲得。
 2 Connector把該請求交給它所在的Service的Engine來處理,並等待Engine的迴應。
 3 Engine獲得請求localhost/test/index.jsp,匹配所有的虛擬主機Host。
 4 Engine匹配到名為localhost的Host(即使匹配不到也把請求交給該Host處理,因為該Host被定義為該Engine的預設主機),名為localhost的Host獲得請求/test/index.jsp,匹配它所擁有的所有的Context。Host匹配到路徑為/test的Context(如果匹配不到就把該請求交給路徑名為“ ”的Context去處理)。
 5 path=“/test”的Context獲得請求/index.jsp,在它的mapping table中尋找出對應的Servlet。Context匹配到URL PATTERN為*.jsp的Servlet,對應於Jsp的Servlet類。
 6 構造HttpServletRequest物件和HttpServletResponse物件,作為引數呼叫Servlet的doGet()或doPost(),執行業務邏輯、資料儲存等程式。
 7 Context把執行完之後的HttpServletResponse物件返回給Host。
 8 Host把HttpServletResponse物件返回給Engine。
 9 Engine把HttpServletResponse物件返回Connector。
10 Connector把HttpServletResponse物件返回給客戶Browser。

 2.5、server.xml配置

 1  1、Server:server.xml的最外層元素。常用屬性:
 2    port:Tomcat監聽shutdown命令的埠。
 3    shutdown:通過指定的埠(port)關閉Tomcat所需的字串。修改shutdown的值,對shutdown.bat無影響
 4  2. Listener:Listener即監聽器,負責監聽特定的事件,當特定事件觸發時,Listener會捕捉到該事件,並做出相應處理。Listener通常用在Tomcat的啟動和關閉過程。Listener可嵌在Server、Engine、Host、Context內。常用屬性:
 5    className:指定實現org.apache.catalina.LifecycleListener介面的類
 6  3. GlobalNamingResources:用於配置JNDI。
 7  4. Service:包裝Executor、Connector、Engine,以組成一個完整的服務, Server可以包含多個Service元件。常用屬性:
 8     className:指定實現org.apache.catalina. Service介面的類,預設值為org.apache.catalina.core.StandardService
 9     name:Service的名字;
10  5. Executor:即Service提供的執行緒池,供Service內各元件使用,常用屬性:
11         className:指定實現org.apache.catalina. Executor介面的類,預設值為org.apache.catalina.core. StandardThreadExecutor
12         name:執行緒池的名字
13         daemon:是否為守護執行緒,預設值為true
14         maxIdleTime:匯流排程數高於minSpareThreads時,空閒執行緒的存活時間(單位:ms),預設值為60000,即1min
15         maxQueueSize:任務佇列上限,預設值為Integer.MAX_VALUE((2147483647),超過此值,將拒絕
16         maxThreads:執行緒池內執行緒數上限,預設值為200
17         minSpareThreads:執行緒池內執行緒數下限,預設值為25
18         namePrefix:執行緒名字的字首。執行緒名字通常為namePrefix+ threadNumber
19         prestartminSpareThreads:是否在Executor啟動時,就生成minSpareThreads個執行緒。預設為false
20         threadPriority:Executor內執行緒的優先順序,預設值為5(Thread.NORM_PRIORITY)
21         threadRenewalDelay:重建執行緒的時間間隔。重建執行緒池內的執行緒時,為了避免執行緒同時重建,每隔threadRenewalDelay(單位:ms)重建一個執行緒。預設值為1000,設定為負則不重建
22 
23 6. Connector是Tomcat接收請求的入口,每個Connector有自己專屬的監聽埠;Connector有兩種:HTTP Connector和AJP Connector;常用屬性:
24     port:Connector接收請求的埠
25     protocol:Connector使用的協議(HTTP/1.1或AJP/1.326   connectionTimeout:每個請求的最長連線時間(單位:ms)
27   redirectPort:處理http請求時,收到一個SSL傳輸請求,該SSL傳輸請求將轉移到此埠處理
28   executor:指定執行緒池,如果沒設定executor,可在Connector標籤內設定maxThreads(預設200)、minSpareThreads(預設10)
29   acceptCount:Connector請求佇列的上限。預設為100。當該Connector的請求佇列超過acceptCount時,將拒絕接收請求
30 
31 7. Engine負責處理Service內的所有請求。它接收來自Connector的請求,並決定傳給哪個Host來處理,Host處理完請求後,將結果返回給Engine,Engine再將結果返回給Connector。常用屬性:
32   name:Engine的名字
33   defaultHost:指定預設Host。Engine接收來自Connector的請求,然後將請求傳遞給defaultHost,defaultHost 負責處理請求
34   className:指定實現org.apache.catalina. Engine介面的類,預設值為org.apache.catalina.core. StandardEngine
35   backgroundProcessorDelay:Engine及其部分子元件(Host、Context)呼叫backgroundProcessor方法的時間間隔。若為負,將不呼叫backgroundProcessor。backgroundProcessorDelay的預設值為10。 Tomcat啟動後,Engine、Host、Context會啟動一個後臺執行緒,定期呼叫backgroundProcessor方法。backgroundProcessor方法主要用於重新載入Web應用程式的類檔案和資源、掃描Session過期。
36    jvmRoute:Tomcat叢集節點的id。部署Tomcat叢集時會用到該屬性,Service內必須包含一個Engine元件;Service包含一個或多個Connector元件,Service內的Connector共享一個Engine
37 
38 8. Host
39         Host負責管理一個或多個Web專案,常用屬性:
40         name:Host的名字
41         appBase:存放Web專案的目錄(絕對路徑、相對路徑均可)
42         unpackWARs:當appBase下有WAR格式的專案時,是否將其解壓(解成目錄結構的Web專案)。設成false,則直接從WAR檔案執行Web專案
43         autoDeploy:是否開啟自動部署。設為true,Tomcat檢測到appBase有新新增的Web專案時,會自動將其部署
44         startStopThreads:執行緒池內的執行緒數量。Tomcat啟動時,Host提供一個執行緒池,用於部署Web專案,startStopThreads為0,並行執行緒數=系統CPU核數;startStopThreads為負數,並行執行緒數=系統CPU核數+startStopThreads,如果(系統CPU核數+startStopThreads)小於1,並行執行緒數設為1;startStopThreads為正數,並行執行緒數= startStopThreads,startStopThreads預設值為1
45         startStopThreads為預設值時,Host只提供一個執行緒,用於部署Host下的所有Web專案。如果Host下的Web專案較多,由於只有一個執行緒負責部署這些專案,因此這些專案將依次部署,最終導致Tomcat的啟動時間較長。此時,修改startStopThreads值,增加Host部署Web專案的並行執行緒數,可降低Tomcat的啟動時間
46 9. Context
47    Context代表一個執行在Host上的Web專案。一個Host上可以有多個Context。將一個Web專案(D:\MyApp)新增到Tomcat,在Host標籤內,新增Context標籤
48 <Context path="" docBase="D:\MyApp"  reloadable="true" crossContext="true">
49 </Context>
50   常用屬性:
51    path:該Web專案的URL入口。path設定為””,輸入http://localhost:8080即可訪問MyApp;path設定為”/test/MyApp”,輸入http://localhost:8080/test/MyApp才能訪問MyApp
52    docBase:Web專案的路徑,絕對路徑、相對路徑均可(相對路徑是相對於CATALINA_HOME\webapps)
53    reloadable:設定為true,Tomcat會自動監控Web專案的/WEB-INF/classes/和/WEB-INF/lib變化,當檢測到變化時,會重新部署Web專案。reloadable預設值為false。通常專案開發過程中設為true,專案釋出的則設為false
54    crossContext:設定為true,該Web專案的Session資訊可以共享給同一host下的其他Web專案。預設為false
55 
56 10. Cluster
57         Tomcat叢集配置。
58 11. Realm可以理解為包含使用者、密碼、角色的”資料庫”。Tomcat定義了多種Realm實現:JDBC Database Realm、DataSource Database Realm、JNDI Directory Realm、UserDatabase Realm等
59 12. Valve可以理解為Tomcat的攔截器,而我們常用filter為專案內的攔截器。Valve可以用於Tomcat的日誌、許可權等。Valve可嵌在Engine、Host、Context內。

   下面看一個server.xml配置例項:

 1 規劃: 
 2 網站網頁目錄:/web/www      域名:www.test1.com 
 3 論壇網頁目錄:/web/bbs     URL:bbs.test1.com/bbs 
 4 網站管理程式:$CATALINA_HOME/wabapps   URL:manager.test.com    允許訪問地址:172.23.136.* 
 5  
 6 conf/server.xml 
 7 <Server port="8005" shutdown="SHUTDOWN"> 
 8   <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> 
 9   <Listener className="org.apache.catalina.core.JasperListener" /> 
10   <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> 
11   <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> 
12   <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> 
13   <GlobalNamingResources> 
14   <!-- 全域性命名資源,來定義一些外部訪問資源,其作用是為所有引擎應用程式所引用的外部資源的定義 --!> 
15     <Resource name="UserDatabase" auth="Container" 
16               type="org.apache.catalina.UserDatabase" 
17               description="User database that can be updated and saved" 
18               factory="org.apache.catalina.users.MemoryUserDatabaseFactory" 
19               pathname="conf/tomcat-users.xml" /> 
20   </GlobalNamingResources> 
21   <!-- 定義的一個名叫“UserDatabase”的認證資源,將conf/tomcat-users.xml載入至記憶體中,在需要認證的時候到記憶體中進行認證 --> 
22   <Service name="Catalina"> 
23   <!-- # 定義Service元件,同來關聯Connector和Engine,一個Engine可以對應多個Connector,每個Service中只能一個Engine --!> 
24     <Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> 
25     <!-- 修改HTTP/1.1的Connector監聽埠為80.客戶端通過瀏覽器訪問的請求,只能通過HTTP傳遞給tomcat。  --> 
26     <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> 
27     <Engine name="Catalina" defaultHost="test.com"> 
28     <!-- 修改當前Engine,預設主機是,www.test.com  --> 
29     <Realm className="org.apache.catalina.realm.LockOutRealm"> 
30         <Realm className="org.apache.catalina.realm.UserDatabaseRealm" 
31                resourceName="UserDatabase"/> 
32     </Realm> 
33     # Realm元件,定義對當前容器內的應用程式訪問的認證,通過外部資源UserDatabase進行認證 
34       <Host name="test.com"  appBase="/web" unpackWARs="true" autoDeploy="true"> 
35       <!--  定義一個主機,域名為:test.com,應用程式的目錄是/web,設定自動部署,自動解壓    --> 
36         <Alias>www.test.com</Alias> 
37         <!--    定義一個別名www.test.com,類似apache的ServerAlias --> 
38         <Context path="" docBase="www/" reloadable="true" /> 
39         <!--    定義該應用程式,訪問路徑"",即訪問www.test.com即可訪問,網頁目錄為:相對於appBase下的www/,即/web/www,並且當該應用程式下web.xml或者類等有相關變化時,自動過載當前配置,即不用重啟tomcat使部署的新應用程式生效  --> 
40         <Context path="/bbs" docBase="/web/bbs" reloadable="true" /> 
41         <!--  定義另外一個獨立的應用程式,訪問路徑為:www.test.com/bbs,該應用程式網頁目錄為/web/bbs   --> 
42         <Valve className="org.apache.catalina.valves.AccessLogValve" directory="/web/www/logs" 
43                prefix="www_access." suffix=".log" 
44                pattern="%h %l %u %t "%r" %s %b" /> 
45         <!--   定義一個Valve元件,用來記錄tomcat的訪問日誌,日誌存放目錄為:/web/www/logs如果定義為相對路徑則是相當於$CATALINA_HOME,並非相對於appBase,這個要注意。定義日誌檔案字首為www_access.並以.log結尾,pattern定義日誌內容格式,具體欄位表示可以檢視tomcat官方文件   --> 
46       </Host> 
47       <Host name="manager.test.com" appBase="webapps" unpackWARs="true" autoDeploy="true"> 
48       <!--   定義一個主機名為man.test.com,應用程式目錄是$CATALINA_HOME/webapps,自動解壓,自動部署   --> 
49         <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="172.23.136.*" /> 
50         <!--   定義遠端地址訪問策略,僅允許172.23.136.*網段訪問該主機,其他的將被拒絕訪問  --> 
51         <Valve className="org.apache.catalina.valves.AccessLogValve" directory="/web/bbs/logs" 
52                prefix="bbs_access." suffix=".log" 
53                pattern="%h %l %u %t "%r" %s %b" /> 
54         <!--   定義該主機的訪問日誌      --> 
55       </Host> 
56     </Engine> 
57   </Service> 
58 </Server> 
59  
60 conf/tomcat-users.xml 
61 <?xml version='1.0' encoding='utf-8'?> 
62 <tomcat-users> 
63   <role rolename="manager-gui" /> 
64   <!--  定義一種角色名為:manager-gui    --> 
65   <user username="cz" password="manager$!!110" roles="manager-gui" /> 
66   <!--  定義一個使用者的使用者名稱以及密碼,並賦予manager-gui的角色    --> 
67 </tomcat-users> 
server.xml配置例項

 2.6、Tomcat 日誌概述

    日誌分為兩種,系統日誌和控制檯日誌。
    系統日誌主要包含執行中日誌和訪問日誌,分為5類:catalina、localhost、manager、localhost_access、host-manager,在logging.properties檔案中進行配置。控制檯日誌包含了catalina日誌,另外包含了程式輸出的日誌(System列印,Console),可以將其日誌配置輸出到檔案catalina.out中。

日誌級別分為如下 7 種:

    SEVERE (highestvalue) > WARNING > INFO > CONFIG > FINE > FINER > FINEST (lowest value)

系統日誌:

1     1、catalina日誌
2         Catalina引擎的日誌檔案,檔名catalina.日期.log
3     2、localhost日誌
4         Tomcat下內部程式碼丟擲異常的日誌,檔名localhost.日期.log
5     3、localhost_access
6         預設 tomcat 不記錄訪問日誌,server.xml檔案中配置Valve可以使 tomcat 記錄訪問日誌
7     4、manager、host-manager
8         Tomcat下預設manager應用日誌

控制檯日誌:

    在Linux系統中,Tomcat 啟動後預設將很多資訊都寫入到 catalina.out 檔案中,我們可以通過tail  -f  catalina.out 來跟蹤Tomcat 和相關應用執行的情況。 在windows下,我們使用startup.bat啟動Tomcat以後,會發現catalina日誌與Linux記錄的內容有很大區別,大多資訊只輸出到螢幕而沒有記錄到catalina.out裡面。,可以通過設定來做到這一點。

三、總結

     在這裡我們瞭解了Tomcat的基本框架和執行的機制,以及相關檔案的配置和日誌的配置,對於Tomcat的原始碼如果我們仔細研讀的話一定會受益匪淺的。

參考文獻:https://blog.csdn.net/u014231646/article/details/79482195

          https://blog.csdn.net/u014231646/article/details/79535925

          https://blog.csdn.net/u014231646/article/details/79525071