深刻浅出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官方文档。
 
上面的配置文件只说起到部分组件或标签,后面会介绍更多的配置信息。
相关文章
相关标签/搜索