tomcat系列之整體結構

本系列文章是基於tomcat6.0的源碼。
首先分析一下tomcat的啓動腳本,windows下的bat
if "%OS%" == "Windows_NT" setlocal
rem ---------------------------------------------------------------------------
rem Start script for the CATALINA Server
rem ---------------------------------------------------------------------------

rem Guess CATALINA_HOME if not defined
set "CURRENT_DIR=%cd%"
if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome

set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"

rem Check that target executable exists
if exist "%EXECUTABLE%" goto okExec
echo Cannot find "%EXECUTABLE%"
echo This file is needed to run this program
goto end
:okExec

rem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs
call "%EXECUTABLE%" start %CMD_LINE_ARGS%
:end

startup.bat腳本,主要完成了環境變量的檢查,該腳本很簡單,主要的工作全部委託給了catalina.bat,這個腳本是啓動tomcat的主腳本,實際上catalina.bat也是檢查各種環境變量的配置,並提供幾種操作,比如啓動,停止debug模式啓動等。鑑於篇幅不一一講解了,我們只關注一下tomcat啓動的main函數在哪?bootstrap.jar就是這個jar包的main函數。org.apache.catalina.startup這個路徑下的Bootstrap類。不過在分析該類時,我們先要熟悉下tomcat的結構是怎樣的?

我們講Tomcat是一個Servlet容器,通過servlet規範對外提供服務,因此Tomcat實質就是一個提供服務的容器,也就是說Tomcat是一個Server,可以把整個Tomcat抽象成一個Server。繼續當我們訪問某個服務的時候,通常通過瀏覽器輸入一個類似下面的地址http://192.168.8.221:8080/explorer/loginInit.do其中指定了ip地址和端口還有詳細的路徑,要能對外提供服務必須指定一個自己的端口與外部通訊,然後TCP通過監聽該端口,獲取指定的消息並解析返回結果,整個過程可惜大概分爲兩個過程,監聽並獲取消息,處理消息,因此可以把這兩部分分開來看,形成兩個不同的組件,監聽並獲取消息的爲Connector,處理消息的爲Continer模塊。我們知道Tomcat是一個Servlet容器,Servlet規範中曾提過應用上下文的概念,其實可以理解爲我們的webapp,因此借鑑這個概念抽象出來Context概念,也是tomcat中的一個組件,爲消息處理模塊。但是當請求過來的時候我們怎麼區分是哪個虛擬主機,來讓Container來區分當然可以,不同的虛擬主機都由它來處理,但是將這個虛擬主機抽象出來似乎是個好的思路,tomcat中將該部分抽象爲Host,虛擬主機可以簡單的理解爲域名,假如我們希望將多個域名映射到一個connector的時候,也即一個Connector組件負責和多個虛擬主機對接,也是非常不方便的,再或者我們希望針對這幾個Host做一些統一的處理,比如攔截消息,非常不方便,因此tomcat抽象出來一個Engine的概念,由Engine充當Host的父組件,充當一個門面。講了這麼多Tomcat大概的體系結構圖就出來了,借用網上別人的一張圖:



上面圖中的組件要比我們講的詳細的多,但主要的組件就那幾個,Server是最頂層的抽象,一個Server下可以有多個Service,一個Service由一個Container和多個Connector組成,Container中有四個子概念,分別爲Engine,Host,Context其中還有一個Wrapper圖中沒有畫出來,Wrapper針對的是Servlet的組件。Tomcat中有那麼多的組件,就像一輛汽車,總得有人把他們組裝起來才能工作吧,才能稱之爲Tomcat吧,沒錯,是需要組裝起來,就像有汽車圖紙一樣,Tomcat中也有這樣一張紙,就是server.xml:
<?xml version='1.0' encoding='utf-8'?>
<!-- Note:  A "Server" is not itself a "Container", so you may not
     define subcomponents such as "Valves" at this level.
     Documentation at /docs/config/server.html
	 注意這裏,Server不是一個Container不能在它下面定義Valves(這個東西后面會提到)
 -->
 <!-- 頂層容器,配置好監聽停止命令的端口-->
<Server port="8005" shutdown="SHUTDOWN">
 配置幾個必須的監聽器,也可以自己實現,最熟悉的是JasperListener,將我們的jsp翻譯成servlet來執行
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
  <Listener className="org.apache.catalina.core.JasperListener" />
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <!-- JMX Support for the Tomcat server. Documentation at /docs/non-existent.html -->
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

  <!-- Global JNDI resources
       Documentation at /docs/jndi-resources-howto.html
  -->
  <!--JNDI使用-->
  <GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <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>

  <!-- 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也不是Container,不能定義子組件Valves
   -->
  <Service name="Catalina">
  
    <!--The connectors can use a shared executor, you can define one or more named thread pools-->
	這裏我們可以定義線程池,如果不定義,tomcat會使用自己的線程池來管理線程
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" 
        maxThreads="150" minSpareThreads="4"/>
    -->
    
    
    <!-- A "Connector" represents an endpoint by which requests are received
         and responses are returned. Documentation at :
         Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
         Java AJP  Connector: /docs/config/ajp.html
         APR (HTTP/AJP) Connector: /docs/apr.html
         Define a non-SSL HTTP/1.1 Connector on port 8080
		 連接器,消息的接受和發送都有它的一個endpoint來完成,常見的是http連接器
		 其實還有兩種ajp,apr
    -->
	這裏配置我們熟悉的端口8080,並且是http連接器
    <Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />
    <!-- A "Connector" using the shared thread pool-->
    <!--
    <Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />
    -->           
    <!-- Define a SSL HTTP/1.1 Connector on port 8443
         This connector uses the JSSE configuration, when using APR, the 
         connector should be using the OpenSSL style configuration
         described in the APR documentation -->
    <!--
    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />
    -->

    <!-- Define an AJP 1.3 Connector on port 8009 -->
	AJP協議,通常的tomcat需要和web服務器比如apache來集成,那麼和apache的通訊就使用到了該connector
    <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">         
    --> 
	默認的Host是localhost,很熟悉吧http://localost:8080/index.html
    <Engine name="Catalina" defaultHost="localhost">

      <!--For clustering, please take a look at documentation at:
          /docs/cluster-howto.html  (simple how to)
          /docs/config/cluster.html (reference documentation) -->
      <!--
	  這個配置項是來配置tomcat集羣的
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
      -->        

      <!-- The request dumper valve dumps useful debugging information about
           the request and response data received and sent by Tomcat.
           Documentation at: /docs/config/valve.html -->
      <!--
	  Valve非常重要的一個概念,這是基於將Request和Response當成消息流的方式來做的實現,
	  將請求流在不同的管道pipeline中流通,其中valve是在pipeline中定義的處理邏輯節點,也即當request
	  到該valve的時候,會執行其中的邏輯,這是很典型的責任鏈模式,非常常用,我們項目就是基於這個模式做的
	  擴展,形成了自己的一套框架。
      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
      -->

      <!-- 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.  -->
		   類似unix中的group,起到一個安全的作用,就是限制權限。
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>

      <!-- Define the default virtual host
           Note: XML Schema validation will not work with Xerces 2.2.
       -->
	   虛擬主機,定義app的基礎目錄,是否解壓等信息
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false">

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

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"  
               prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>
        -->

      </Host>
    </Engine>
  </Service>
</Server>

這個就是圖紙,定義了層級關係,初始化的動作由tomcat應用digester完成,簡單提下digester是一個解析xml的工具也是apache的,通過定義個xml並且指定規則,來解析相應的xml,有很多優秀的解析xml工具,比如xtream使用起來非常簡便。

上面就是tomcat的大體概況,詳細的東西還得深入到源碼去探究,怎樣去下載編譯tomcat源碼,這裏就不介紹了,網上百度一下有很多,善於借鑑別人的經驗爲己所用,也是一種能力



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章