1. 程式人生 > >Tomcat基本架構解析(Tomcat架構解析學習筆記)

Tomcat基本架構解析(Tomcat架構解析學習筆記)

1.Tomcat元件架構設計

 

    1)server

        伺服器可以描述為這樣一個應用:接收客戶端發來的請求資料並進行解析,完成相關業務處理,然後把處理結果作為相應返回給客戶端。

        通常我們可以使用serversocket監聽指定埠來實現該功能

 

    2)Connection和Container(Engine)

        當我們將請求監聽和請求處理放在一起的時候擴充套件性就很差。比如當我們想適配多種網路協議,但是請求處理卻相同的時候。

        處理方案就是:將網路協議和請求處理從概念上分開。Connection負責開啟socket並監聽客戶端請求、返回響應資料;Container(Engine)負責具體的請求處理。

 

    3)Service

        上述方案的缺陷就是無法很好的判斷Connection由哪個Container(Engine)來處理。

        採用service方案,一個server包含多個service(它們相互獨立),一個service包含多個Connection和一個Container,這樣,connection的請求只能由該container來處理

        由於Container表示一個更加通用的概念,為了與Tomcat元件命名一致,將Container重新命名為Engine,用於表示整個servlet引擎

 

    4)Context

        上述解決了網路協議和容器的解耦。下面我們需要在Engine中支援管理web應用。當接收到Connection請求時,能夠找到一個合適的Web應用來處理。Context就代表一個Web應用

 

    5)Host

        為了提供對多個域名的服務,我們可以將每個域名視為一個虛擬的主機。在每個Host下包含多個Context

       

    6)Wrapper

        在一個Web應用中,可以包含多個servlet例項來處理不同連結的請求。因此,需要一個元件概念來表示Servlet定義,在Tomcat中servlet定義被稱為Wrapper

 

    7)Container

        容器代表一類元件,這類元件的作用就是接收客戶端請求並返回響應資料,具體操作委派到子元件完成。

        Engine、Host、Context、Wrapper均繼承自Container

    8)LifeCycle

        所有的元件均存在啟動、停止等生命週期方法,擁有生命週期管理的特性,我們將這個抽取出來作為介面LifeCycle,定義生命週期管理的核心方法。

    9)Executor

        tomcat的併發,提供了Executor介面來表示一個可以在元件間共享的執行緒池。該介面同樣繼承LifeCycle介面

        共享範圍:Executor由Service維護,因此同一個Service中的元件可以共享一個執行緒池

        

    10)Bootstrap和Catalina

        Catalina提供一個shell程式,用於解析service.xml建立各個元件。同時負責啟動、停止應用伺服器

        Bootstrap作為應用伺服器啟動入口。Bootstrap負責建立Catalina,根據執行引數呼叫Catalina相關方方法完成對應用伺服器的操作

 

    總結:

        * Server 表示整個servlet容器,因此Tomcat容器中只有一個Server例項

        * Service 表示一個或多個Connector的集合。這些Connector共享同一個Container來處理其他請求。在一個Server中可以包含多個Service,這些Service相互獨立

        * Connector Tomcat聯結器,用於監聽並轉換為Socket請求,將該請求交由Container處理,支援不同的協議及不同IO方式

        * Container 表示能夠接收請求並返回響應的一類物件。在Tomcat中存在不同級別的容器:Engine、Host、Context、Wrapper

        * Engine 表示整個Servlet引擎,Engine為最高級別的容器。儘量Engine不是直接處理請求的容器卻是獲得目標容器的入口

        * Host 表示Engine中的虛擬機器,與一個伺服器的網路名有關,如域名等。客戶端可以使用這個網路名連線伺服器,這個名稱必須要在DNS伺服器上註冊

        * Context 用於表示ServletContext,在Servlet規範中,一個ServletContext表示一個Web應用

        * Wrapper 表示Web應用中定義的Servlet

        * Executor 表示Tomcat元件間可以共享的執行緒池

 

 

2.請求處理過程

 

    從本質上講,應用伺服器的處理開始於監聽的Socket埠接收到資料,結束於將處理結果寫入Socket輸出流

    * 應用伺服器將請求按照既定協議進行讀取,並將其封裝為與具體協議無關的請求體

    * 按照請求對映規則將請求定位到具體的處理單元(使用框架的話SpringMVC等則會將請求匹配到Servlet下的一個控制器)

    * 業務處理結束,將結果封裝到一個與協議無關的響應物件

 

3.Tomcat類載入方案

 

    應用伺服器通常會建立類載入器以實現更靈活的控制。

    * 隔離性:Web應用類庫互相隔離,避免依賴庫或應用包相互影響。設想有兩個應用,一個採取Spring2.X,一個採取Spring4.X,而應用伺服器使用同一個類載入器,那麼應用之間會因為jar包覆蓋導致無法啟動

    * 靈活性:Web應用之間的類載入器相互獨立,我們就能只針對一個Web應用重新部署

    * 效能:每個Web應用都有一個類載入器,則Web應用在載入類時,不會搜尋其他Web應用包含的jar包,效能自然高

    1)Common 位於Tomcat頂層的公共類載入器,預設指向Tomcat_home/lib下的包

    2)Catalina 用於載入Tomcat應用伺服器的類載入器,路徑為server.loader,預設為空

    3)Shared 所有web應用的父載入器,路徑為shared.loader,預設為空

    4)Web 載入WEB-INF/classes下的未壓縮的class、資原始檔及WEB-INFO/lib下的jar包,該類載入器只對當前web應用可見

 

    在catalina.jar org.apache.catalina.loader包下可以看到關於ClassLoader的實現

 

 

4.通過server.xml來檢視Tomcat各元件之間的關係

    我們在Eclipse中建立一個web專案,springweb,並在Eclipse中關聯Tomcat8.5,並在Tomcat中關聯springweb,啟動Tomcat,可以看到生成的server.xml如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
  <!-- Security listener. Documentation at /docs/config/listeners.html
  <Listener className="org.apache.catalina.security.SecurityListener" />
  -->
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>

  
  <GlobalNamingResources>
   
    <Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
  </GlobalNamingResources>

  <!-- A "Service" is a collection of one or more "Connectors" that share
       a single "Container" Note:  A "Service" is not itself a "Container",
       so you may not define subcomponents such as "Valves" at this level.
       Documentation at /docs/config/service.html
   -->
  <Service name="Catalina">
    <!-- A "Connector" represents an endpoint by which requests are received
         and responses are returned. Documentation at :
         Java HTTP Connector: /docs/config/http.html
         Java AJP  Connector: /docs/config/ajp.html
         APR (HTTP/AJP) Connector: /docs/apr.html
         Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
    -->
    <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>


    <!-- An Engine represents the entry point (within Catalina) that processes
         every request.  The Engine implementation for Tomcat stand alone
         analyzes the HTTP headers included with the request, and passes them
         on to the appropriate Host (virtual host).
         Documentation at /docs/config/engine.html -->

    <!-- You should set jvmRoute to support load-balancing via AJP ie :
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
    -->
    <Engine defaultHost="localhost" name="Catalina">
      <!-- Use the LockOutRealm to prevent attempts to guess user passwords
           via a brute-force attack -->
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <!-- This Realm uses the UserDatabase configured in the global JNDI
             resources under the key "UserDatabase".  Any edits
             that are performed against this UserDatabase are immediately
             available for use by the Realm.  -->
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
      </Realm>

      <Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">

        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log" suffix=".txt"/>

      <Context docBase="springweb" path="/springweb" reloadable="true" source="org.eclipse.jst.jee.server:springweb"/></Host>
    </Engine>
  </Service>
</Server>

    由上可知,Tomcat結構圖可如下所示:

    * Tomcat只要一個Server,一個Server可以有多個Service,一個Service可以有多個Connection和Container

    * Server掌管整個Tomcat的生死大權

    * Service是對外提供服務的

    * Connector用於接收請求並將請求封裝成Request和Response來具體處理

    * Container用於管理和封裝Servlet,以及處理具體Request請求

 

參考:Tomcat架構解析(劉光瑞)