天天看點

Tomcat源碼分析(二):配置檔案server.xml解讀

前言

tomcat源碼都是圍繞着server.xml這個配置檔案展開來看的,是以我們分析它的源碼也需要從它開始入手。

概覽

Tomcat的組織結構很簡單,下面一張圖能夠清晰的展示出來。

Tomcat源碼分析(二):配置檔案server.xml解讀

Server是Tomcat中最頂層的容器,代表着整個伺服器,一個Server可以包含至少一個Service,用于具體提供服務。

Service主要包含兩個核心元件:Connector和Container。

Connector元件負責處理請求監聽,一個Connector與一個TCP端口綁定,接受Socket請求并将請求封裝成Request和Response

Container元件負責處理請求處理,用于封裝和管理Servlet,以及具體處理Request請求

至于具體的請求,我們通過源碼說明。

配置檔案源碼分析

每個元件都能夠在源碼中展現出來,這裡我提供一份自己添加了注釋的配置檔案,可以參照了解。

并且我會在下面對核心元件進行具體分析。

<?xml version='1.0' encoding='utf-8'?>

<!--
Server是一個頂級元件,代表了一個Tomcat執行個體,一個JVM程序中隻能有一個Server執行個體。
Tomcat提供了一個實作了 org.apache.catalina.Server接口的 org.apache.catalina.core.StandardServer預設類,讀取Server元素配置。

Server是配置檔案中的最外層元素,支援以下屬性:
      className:指定要使用的實作類(必須實作org.apache.catalina.Server接口)名稱。如果不指定,預設使用标準實作類StandardServer。
      address:等待shutdown指令的伺服器IP位址,預設是localhost。
      port:等待shutdown指令的監聽端口,如果設定為-1,表示關閉shutdown端口。
      shutdown:指定終止Tomcat伺服器運作時,發給Tomcat伺服器的shutdown監聽端口的字元串.該屬性必須設定 。
-->
<Server port="8015" shutdown="SHUTDOWN">
    <Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
    <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on"/>
    <Listener className="org.apache.catalina.core.JasperListener"/>
    <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
    <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
    <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>

    <!--定義的全局JNDI資源-->
    <GlobalNamingResources>
        <Resource name="UserDatabase" auth="Container"
                  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"/>
    </GlobalNamingResources>

    <!--Server元素中可以有一個或多個Service,每個Service關聯了多個Connector和一個Engine。
    Service支援兩個屬性:
        className:指定要使用的實作類(必須實作org.apache.catalina.Service接口)名稱。如果不指定,預設使用标準實作類StandardService。
        name:Service的名稱,在同一個Server元素中必須唯一,預設是Catalina。
    -->
    <Service name="Catalina">

        <!--Connector負責處理請求監聽,一個Connector與一個TCP端口綁定,接受請求并将請求封裝成Request和Response,Service中預設包含兩個Connector。
            Connector支援四個屬性:
                port:屬性指定監聽端口,預設8080端口,可修改為1024-65535間的任意一個端口
                protocol:支援協定
                connectionTimeout:定義連接配接器等待時間,預設20秒
                redirectPort:SSL請求會重定向到8443端口
        -->
        <!--HTTP/1.1:處理HTTP請求,此連接配接器使Tomcat可以作為HTTP伺服器使用。-->
        <Connector port="8090" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8453"/>
        <!--AJP/1.3:Apache JServ 協定處理Tomcat與Apache之間的通信。Tomcat核心功能是解析Servlet,html和圖檔解析功能相對其他HTTP伺服器較弱(如Apache HTTP Server),是以,一般都是內建使用,Apache處理靜态頁面請求,Tomcat處理Servlet/JSP請求。-->
        <Connector port="8019" protocol="AJP/1.3" redirectPort="8453"/>

        <!--Container負責處理請求處理,有四個子容器:Engine、Host、Context和Wrapper,他們之間是父子包含關系。-->
        <!--一個Service隻有一個Engine,表示整個Servlet引擎,其主要作用是執行業務邏輯;從HTTP Connector接收HTTP請求,并且會根據主機名/IP位址交由相應的主機處理請求。-->
        <Engine name="Catalina" defaultHost="localhost">
            <Realm className="org.apache.catalina.realm.LockOutRealm">
                <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
            </Realm>

            <!--Host,代表一個站點,也可以叫虛拟主機,一個Engine下面可以包含一個或者多個Host,即一個Tomcat執行個體可以配置多個虛拟主機-->
                <!--appBase:定義了應用程式的根目錄,預設是webapps-->
                <!--unpackWARS:定義了是否解壓webapps中的WAR檔案,如果指定為“false”,會從WAR檔案直接運作程式,執行較慢-->
                <!--autoDeploy:把應用程式直接拖到webapps目錄下,是否自動運作-->
            <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
                <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b"/>
                <!--
                Context,代表一個應用程式
                    path:通路項目時的URL,加在localhost:8080後
                    docBase:path對應的項目目錄
                    reloadable:監視 /WEB-INF/classes/ 和 /WEB-INF/lib目錄中的類檔案,更改後自動重載應用程式,
                    生成環境不建議使用,預設為“false”
                -->
                <Context path="/image" docBase="/opt/file/img" reloadable="false"></Context>
                <!--Wrapper針對的是每個具體的servlet-->
            </Host>
        </Engine>
    </Service>
</Server>

           

tomcat的核心元件

介紹下tomcat的核心元件Connector元件和Container元件

Connector元件

Connector元件負責處理請求監聽,一個Connector與一個TCP端口綁定,接受Socket請求并将請求封裝成Request和Response對象,然後将産生的 Request 和 Response 對象傳給處理Engine(Container中的一部分),真正處理請求的是Engine。

Tomcat源碼分析(二):配置檔案server.xml解讀

Service中預設包含兩個Connector,HTTP協定和AJP協定,HTTP協定接收http請求,使Tomcat可以作為HTTP伺服器使用。AJP協定處理Tomcat和Apache伺服器之間的請求。

Connector在Tomcat中的設計如圖所示。這裡不深入讨論,後續再深入。

Tomcat源碼分析(二):配置檔案server.xml解讀

Container元件

Container負責處理請求處理,Container是容器的父接口,有四個子容器:Engine、Host、Context和Wrapper,他們之間是父子包含關系。體系結構如下:

Tomcat源碼分析(二):配置檔案server.xml解讀
  • Engine 容器

    一個Service隻有一個Engine,表示整個Servlet引擎,其主要作用是執行業務邏輯;從HTTP Connector接收HTTP請求,并且會根據主機名/IP位址交由相應的主機處理請求。uml類圖如下

    Tomcat源碼分析(二):配置檔案server.xml解讀
  • Host 容器

    代表一個站點,也可以叫虛拟主機,一個Engine下面可以包含一個或者多個Host,即一個Tomcat執行個體可以配置多個虛拟主機,uml類圖如下。

    Tomcat源碼分析(二):配置檔案server.xml解讀
  • Context 容器

    Context 代表 Servlet 的 Context,它具備了 Servlet 運作的基本環境,理論上隻要有 Context 就能運作 Servlet 了。簡單的 Tomcat 可以沒有 Engine 和 Host。Context 最重要的功能就是管理它裡面的 Servlet 執行個體,Servlet 執行個體在 Context 中是以 Wrapper 出現的,uml類圖如下。

    Tomcat源碼分析(二):配置檔案server.xml解讀
  • Wrapper 容器

    Wrapper 代表一個 Servlet,它負責管理一個 Servlet,包括的 Servlet 的裝載、初始化、執行以及資源回收。Wrapper 是最底層的容器,它沒有子容器了,是以調用它的 addChild 将會報錯。

    Wrapper 的實作類是 StandardWrapper,StandardWrapper 還實作了擁有一個 Servlet 初始化資訊的 ServletConfig,由此看出 StandardWrapper 将直接和 Servlet 的各種資訊打交道。uml類圖如下。

    Tomcat源碼分析(二):配置檔案server.xml解讀

tomcat其他元件

Tomcat 還有其它重要的元件,如安全元件 security、logger 日志元件、session、mbeans、naming 等其它元件。這些元件共同為 Connector 和 Container 提供必要的服務。

小結

現在我們了解了,tomcat的整體結構大概是這個樣子。

Tomcat源碼分析(二):配置檔案server.xml解讀

整個啟動流程也是很标準化的,入口是BootStrap,統一按照生命周期管理接口Lifecycle的定義進行啟動。首先,調用init()方法逐級初始化,接着調用start()方法進行啟動,同時,每次調用伴随着生命周期狀态變更事件的觸發。

每一級元件除完成自身的處理外,還有負責調用子元件的相關調用,元件群組件之間是松耦合的,可以通過配置進行修改。

Tomcat源碼分析(二):配置檔案server.xml解讀

學習tomcat的源碼,參考了https://blog.csdn.net/w1992wishes/article/details/79242797這篇文章,感覺寫的不錯,可以參考下。