深刻淺出Tomcat/1- 來歷和配置文件

背景

Tomcat是一個很是重要的Web Server,已經存在多年。尤爲是最近幾年,由於Spring MVC或是Spring Boot的盛行,Tomcat的地位愈加重要,地位明顯升級。
 
我相信不少人通常只是停留在使用的基礎上,可是想利用Tomcat實現一些複雜的場景或者高級同功能,咱們就須要進一步學習,也須要咱們把Tomcat的基礎弄清楚。
 
本文將經過大量代碼和實例詳細講解Tomcat的基礎知識,以便咱們對Tomcat有個一個總體深刻的認識。
 
本文的代碼基於Tomcat 9. 代碼地址在 https://github.com/apache/tomcat

Tomcat和Catalina的來歷

你們都在使用Tomcat,可是我問Tomcat的來歷是什麼,爲何要會用Catalina,我認爲不是每一個人都知道。是的,Tomcat和Catalina是2個很是重要的名詞,在Tomcat軟件和配置裏隨處可見,可是爲何做者取這樣的名字呢?聽說,當時做者Craig寫代碼時,家裏的貓有時候不停的跳來跳去,因此最後有Tomcat的取名,那Catalina呢?做者有一個很是喜歡的島,叫Catalina Island,聽說這個島儘管做者知道,可是還沒去過,不知道如今去過沒有。因此就用Catalina取名了。
在這個島上有個鎮,叫Avalon,Tomcat曾經取過Avalon的名字,只不事後來放棄了。

Tomcat配置文件

瞭解Tomcat的結構,最直接的辦法是從Tomcat的配置文件看起。下面是Tomcat的配置文件(conf/server.xml),這個是Tomcat源碼裏的默認配置文件。
爲了簡單,我刪除了一些註釋等。
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <!-- 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" />

  <!-- Global JNDI resources
       Documentation at /docs/jndi-resources-howto.html
  -->
  <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 name="Catalina">


    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               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 name="Catalina" defaultHost="localhost">


      <!-- 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 name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">


        <!-- 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"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>
    </Engine>
  </Service>
</Server>
咱們能夠看到Server、Service、Connector、Engine、Host等。那麼它們之間有什麼關係呢?

 

從以上能夠看出,Tomcat最頂層的容器叫Server,表明整個服務器,Server中包一個或多個Service,該Service用來表明一個服務。同時,一個Service也包含多個Connector,Connector用來網絡鏈接,例如HTTP,HTTPS或AJP。Service也包含一個或多個Engine等,用來管理和封裝Servlet,以及處理具體的請求等。html

咱們先簡要解釋一下Tomcat的這個配置文件。java

Server
Server的配置文件以下:
<Server port="8005" shutdown="SHUTDOWN"> 
port是8005,也就是說端口8005會監聽SHUTDOWN的命令,當咱們使用tomcat目錄下的bin/shutdown.sh去中止Tomcat時,就會往8005端口發送一個SHUTDOWN的命令。固然,若是端口8005關閉了,執行shutdown.sh腳本就會報錯,只能kill Tomcat的進程了。
 
Listener
<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 className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!-- 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" /> 
先看第一個VersionLoggerListener,其實就是打印Tomcat的一些相關信息,例如版本號,OS信息,Java版本信息等。
@Override
public void lifecycleEvent(LifecycleEvent event) {
    if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) {
        log();
    }
}
 
 
private void log() {
    log.info(sm.getString("versionLoggerListener.serverInfo.server.version",
            ServerInfo.getServerInfo()));
    log.info(sm.getString("versionLoggerListener.serverInfo.server.built",
            ServerInfo.getServerBuilt()));
    log.info(sm.getString("versionLoggerListener.serverInfo.server.number",
            ServerInfo.getServerNumber()));
    log.info(sm.getString("versionLoggerListener.os.name",
            System.getProperty("os.name")));
    log.info(sm.getString("versionLoggerListener.os.version",
            System.getProperty("os.version")));
    log.info(sm.getString("versionLoggerListener.os.arch",
            System.getProperty("os.arch")));
    log.info(sm.getString("versionLoggerListener.java.home",
            System.getProperty("java.home")));
    log.info(sm.getString("versionLoggerListener.vm.version",
            System.getProperty("java.runtime.version")));
    log.info(sm.getString("versionLoggerListener.vm.vendor",
            System.getProperty("java.vm.vendor")));
    log.info(sm.getString("versionLoggerListener.catalina.base",
            System.getProperty("catalina.base")));
    log.info(sm.getString("versionLoggerListener.catalina.home",
            System.getProperty("catalina.home")));
 
    if (logArgs) {
        List<String> args = ManagementFactory.getRuntimeMXBean().getInputArguments();
        for (String arg : args) {
            log.info(sm.getString("versionLoggerListener.arg", arg));
        }
    }
 
    if (logEnv) {
        SortedMap<String, String> sortedMap = new TreeMap<>(System.getenv());
        for (Map.Entry<String, String> e : sortedMap.entrySet()) {
            log.info(sm.getString("versionLoggerListener.env", e.getKey(), e.getValue()));
        }
    }
 
    if (logProps) {
        SortedMap<String, String> sortedMap = new TreeMap<>();
        for (Map.Entry<Object, Object> e : System.getProperties().entrySet()) {
            sortedMap.put(String.valueOf(e.getKey()), String.valueOf(e.getValue()));
        }
        for (Map.Entry<String, String> e : sortedMap.entrySet()) {
            log.info(sm.getString("versionLoggerListener.prop", e.getKey(), e.getValue()));
        }
    }

 

 
再看看AprLifecycleListener。其實主要是實如今Tomcat的生命週期裏,APR的初始化,建立和銷燬等。
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
它們都會實現接口 LifecycleListener。該接口爲某些事件定義一個listener,這裏的事件,其實就是組件的啓動和中止事件。可是組件須要實現Tomcat生命週期的接口。這個在後面講。
 
接下來就是GlobalNamingResources,它定義一些全局的JNDI資源,例如數據庫鏈接等,JNDI意思是Java Naming and Directory interface。
 
而後就是Service,name爲Catalina.繼續往下看,接下來就是Connector,它主要用來處理網絡鏈接,封裝消息包,不一樣的協議會有不一樣的處理方式,例如port爲8080,協議爲HTTP/1.1,會有對應的ProtocolHander來處理,這會在後面解釋。能夠擁有多個Connector。
下面就是Engine,有點相似虛擬主機的意思,有個defaultHost屬性,是指在找不到虛擬主機時用的。Realm主要用來作安全域,後面也會降到。
 
Valve是Tomcat一個很是重要的概念,和Pipeline配合使用,在這裏設置的是一個關於Tomcat log的Valve,主要用於將Tomcat的日誌以某種格式打印到往到文件,className是其實現類,prefix是日誌文件的前綴,suffix是後綴,2者組合起來就是文件名了。Pattern是日誌內容的pattern,能夠將request的屬性打印到文件裏,具體如何打印還得參看Tomcat官方文檔。
 
上面的配置文件只說起到部分組件或標籤,後面會介紹更多的配置信息。
相關文章
相關標籤/搜索