Tomcat的核心组件以及server.xml配置全解【一万字】

·  阅读 687

这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战

详细介绍了Tomcat的核心组件以及server.xml配置全解,以及请求处理流程。

前面我们简单介绍了Tomcat服务器的基本概念,现在我们来简单看看它的核心配置文件server.xml。

本文将会介绍Tomcat中比较重要的一些配置和概念,而又不会太深入底层,本文并不是专业的Tomcat学习文章。如果你是Java学习者或者开发者,并且没有专门的时间和计划去详细学习Tomcat服务器,那么本文值得一看!

1 server.xml文件概述

tomcat是组件式架构,它的server.xml配置文件中可以通过标签配置tomcat容器中的不同类型的组件,是tomcat的核心配置文件。

server.xml中的主要组件(标签)的关系如下(并没有展示全部组件的关系):

在这里插入图片描述

Server标签在最顶层,代表整个Tomcat容器;一个Server元素中可以有一个或多个Service元素。

Service在Connector和Engine外面包了一层,把它们组装在一起,对外提供服务。一个Service可以包含多个Connector,但是只能包含一个Engine;Connector接收请求,Engine处理请求。

Engine、Host和Context都是容器,且 Engine包含Host,Host包含Context。每个Host组件代表Engine中的一个虚拟主机;每个Context组件代表在特定Host上运行的一个Web应用。

tomcat 8.5.61的默认server.xml的配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<!--
Server是server.xml的最外层标签,代表整个tomcat容器
它的内部不能直接定义<Value/>组件
-->
<Server port="8005" shutdown="SHUTDOWN">
    <!--监听器组件-->
    <Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
    <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on"/>
    <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
    <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
    <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>

    <!--配置全局JNDI资源-->
    <GlobalNamingResources>
        <!-- 用户数据库Realm,也可以用于对用户进行身份验证的可编辑用户数据库 -->
        <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>

    <!--
    将<Engine/>标签和<Connector/>标签组合在一起,对外提供服务,一个Server元素中可以有一个或多个Service元素
    包含一个<Engine/>标签,以及一个或多个<Connector/>标签,<Connector/>标签共享用同一个<Engine/>标签
    它的内部不能直接定义<Value/>组件
    -->
    <Service name="Catalina">
        <!-- 供Service内各个Connector组件共享使用的线程池执行器,我们可以定义的多个命名线程池 -->
        <!--
        <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
            maxThreads="150" minSpareThreads="4"/>
        -->


        <!-- 连接器组件,主要用于接收连接请求,创建Request和Response对象用于和请求端交换数据
             然后分配线程让Engine来处理这个请求,并把产生的Request和Response对象传给Engine。

             在端口8080上定义使用HTTP/1.1协议的连接器,这就是默认连接器,基于BIO运行模式
        -->
        <Connector port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443"/>

        <!-- 使用指定命名共享线程池的连接器 -->
        <!--
        <Connector executor="tomcatThreadPool"
                   port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443" />
        -->

        <!--在端口8443上定义使用Http11NioProtocol协议的连接器,是一个基于Non-blocking 的 NIO运行模式的Connector,即非阻塞IO,性能更好-->
        <!--
        <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
                   maxThreads="150" SSLEnabled="true">
            <SSLHostConfig>
                <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
                             type="RSA" />
            </SSLHostConfig>
        </Connector>
        -->

        <!--在端口8443上定义使用Apr运行模式的连接器,在高并发下性能相比于NIO的连接器更加优越-->
        <!--
        <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
                   maxThreads="150" SSLEnabled="true" >
            <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
            <SSLHostConfig>
                <Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
                             certificateFile="conf/localhost-rsa-cert.pem"
                             certificateChainFile="conf/localhost-rsa-chain.pem"
                             type="RSA" />
            </SSLHostConfig>
        </Connector>
        -->

        <!--在端口8009上定义使用AJP/1.3协议访问的连接器-->
        <!--
        <Connector protocol="AJP/1.3"
                   address="::1"
                   port="8009"
                   redirectPort="8443" />
        -->

        <!--
        请求处理组件,一个Service标签只能有一个Engine标签
        Engine组件从一个或多个Connector中接收请求并处理,并将完成的响应返回给Connector,最终响应给客户端。
        -->
        <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集群配置组件,详情参考:
            /docs/cluster-howto.html(简单配置)
            /docs/config/cluster.html(reference documentation)
            -->
            <!--
            <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
            -->

            <!-- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack -->
            <!--
            Realm可以理解为包含用户名、密码、角色的"数据库",或者"域"
            Realm提供了一种用户密码与web应用的映射关系,从而达到角色安全管理的作用
            这里使用 LockOutRealm 防止试图通过暴力攻击猜测用户密码
            -->
            <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>
            <!--
            一个虚拟主机,可以指定应用程序的基本目录,包含了一个或多个Web应用
            默认的虚拟主机名为"localhost",
            -->
            <Host name="localhost" appBase="webapps"
                  unpackWARs="true" autoDeploy="true">
                <!--通过日志记录其该Host中处理的所有请求-->
                <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>
复制代码

下面来简单的认识一下核心组件(标签)的作用以及配置。本文以tomcat 8.5.61版本为主。

2 Server

Server标签是server.xml文件的根标签,代表整个tomcat的Servlet容器,时tomcat的核心组件,是Tomcat实例的顶层的org.apache.catalina.Server接口的抽象。

Server标签的属性表示 servlet 容器的一个整体的特征。常见属性如下:

属性名描述
className要使用的Java 实现类全路径名,指定的类必须实现org.apache.catalina.Server.Server 接口。如果未指定类名,则将使用标准实现,即org.apache.catalina.core.StandardServer
addresstomcat监听shutdown命令的TCP/IP地址,如未指定,则默认为localhost
porttomcat监听shutdown命令的TCP/IP端口号,默认为8005。设置为-1,表示禁止通过端口关闭Tomcat,此时shutdown.bat命令不能使用。如果一台及其启动多个tomcat实例,该端口应该不一致。
shutdown通过指定的地址(address)和端口(port)关闭tomcat时所需发送的终止字符串,默认为“SHUTDOWN”,修改shutdown的值,对shutdown.bat的使用无影响。

Server标签内部可以配置一个或者多个Listener标签,一个或者多个Service标签以及一个GlobalNamingResources标签。

2 Listener

一个Listener标签表示配置的一个tomcat的监听器组件。一个监听器负责监听特定的事件,当特定事件触发时,Listener会捕捉到该事件并做出相应处理。

Listener可嵌在Server、Engine、Host、Context标签内,不得将任何其他标签元素嵌套在监听器标签中。某些特殊类型的监听器仅用于嵌套在特定标签中,默认配置的监听器都是在Server标签内。Listener通常用于监听Tomcat的启动和关闭事件。

所有监听器都有的属性如下:

属性名描述
className要使用的Java 监听器实现类全路径名,指定的类必须实现org.apache.catalina.LifecycleListener 接口。

本文使用的tomcat版本中,默认开启的五个监听器配置如下:

在这里插入图片描述

常见的监听器介绍如下:

  1. VersionLoggerListener :版本日志记录生命周期监听器。当Tomcat启动时,该监听器记录Tomcat、Java和操作系统的信息。该类型的监听器必须只能嵌套在Server标签中,并且必须是配置的第一个监听器。
  2. AprLifecycleListener :APR 生命周期监听器。Tomcat启动时检查APR库,如果存在则加载。APR,即Apache Portable Runtime,是Apache可移植运行库,可以实现高可扩展性、高性能,以及与本地服务器技术更好的集成。该类型的监听器必须只能嵌套在Server标签中。Tomcat将以JNI的形式调用Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地提高Tomcat对静态文件的处理性能。
  3. JreMemoryLeakPreventionListener:JRE 内存泄漏防护监听器。这个监听器会导致每小时就执行一次full GC操作,因此可以直接关闭这个监听器,或者添加gcDaemonProtection="false"属性来进制监听。该类型的监听器必须只能嵌套在Server标签中。
  4. GlobalResourcesLifecycleListener:全局资源生命周期监听器。通过该监听器,可以初始化< GlobalNamingResources/>标签中定义的全局JNDI资源;如果没有该监听器,任何全局资源都不能使用。该类型的监听器必须只能嵌套在Server标签中。
  5. ThreadLocalLeakPreventionListener:ThreadLocal泄漏防护监听器。当一个Web应用(context标签)停止时,该监听器器将触发执行器池中的线程更新,以避免线程本地相关内存泄漏。当线程执行完任务被收回线程池时,活跃线程会一个一个的更新。只有当Web应用(context标签)的renewThreadsWhenStoppingContext属性设置为true时,该监听器才有效。
  6. SecurityListener:安全生命周期监听器。当 Tomcat 启动时,该监听器将执行许多安全检查,并防止 Tomcat 在检查失败时启动。默认情况下未启用该侦听器。
  7. JasperListener:在Web应用启动之前初始化Jasper,Jasper是JSP引擎,把JVM不认识的JSP文件解析成java文件,然后编译成class文件供JVM使用。

3 GlobalNamingResources

全局命名资源组件,定义服务器的全局JNDI资源,所有的应用程序都可以引用。通常可以包含三个子标签:Environment、Resource、ResourceEnvRef。

JNDI(Java Naming and Directory Interface)多用于java的数据库连接中,我们常见的就是JDBC,在JDBC中,连接数据库需要用户名、用户名密码和数据库名称等参数,将来如果这三个参数中的任何一个修改,则整个程序中相关的地方都需要修改,简直是牵一发而动全身,因此出现JNDI技术。

在JNDI中,将连接数据库需要的用户、用户密码和数据库名称等JDBC引用的参数定义为一个整体(即这个整体中包含JDBC要用到类库、数据库驱动程序、用户、用户密码等),然后为这个整体设置一个名称,这个整体保存在应用程序之外的文件中,这样以后连接数据库的时候直接在程序中引用这个整体的名称即可,无论用户、用户密码怎么变换,只要这个整体的名称不变,我们仅要修改这个外部的整体的用户和用户密码,而无需修改整个程序。这里的这个整体就是JNDI数据源(JNDI资源)。对于数据库来说,JNDI数据源避免了程序与数据库之间的紧耦合,使应用更加易于配置、易于部署。

3.1 Environment

Environment标签可以用于配置全部项目的环境变量。比如:

<GlobalNamingResources ...>
...
<Environment name="maxExemptions" value="10"
       type="java.lang.Integer" override="false"/>
...
</GlobalNamingResources>
复制代码

它表示配置一个名为maxExemptions的Integer类型的环境变量,值为10。如果想要在具体的Web应用中引用该常量,那么在具体应用的Context标签下,使用ResourceLink标签引用该Environment资源,global属性就是该Environment的name属性名字。

这等同于在web应用的/WEB-INF/web.xml文件中的如下配置:

<env-entry>
  <env-entry-name>maxExemptions</env-entry-name>
  <env-entry-value>10</env-entry-value>
  <env-entry-type>java.lang.Integer</env-entry-type>
</env-entry>
复制代码

在Java代码中使用如下方式读取:

Context initCtx = null;
initCtx = new InitialContext();
Context envCtx = (Context)initCtx.lookup("java:comp/env");
Integer n = (Integer)envCtx.lookup("maxExemptions");
复制代码

3.2 Resource

Resource标签可以用于配置各种全局数据源,最常见的就是用户数据库连接JNDI源。下面表示通过JNDI配置一个数据库数据源。

<GlobalNamingResources>       
    <Resource 
      name="DbSource" 
      username="admin"
      password="123456" 
      maxIdle="30" 
      maxActive="50"
      maxWait="5000"
      type="javax.sql.DataSource"
      driverClassName="com.mysql.jdbc.Driver" 
      url="jdbc:xxx" />
</GlobalNamingResources>
复制代码

然后在Web应用(context标签)下通过ResourceLink标签引用数据源:

<ResourceLink global="DbSource" name="DbSource" type="javax.sql.DataSource"/>
复制代码

随后在Spring配置文件中可以配置引用JNDI数据源:

<beans>
  <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName">
        <value>java:/comp/env/ DbSource</value>
    </property> 
  </bean>
</beans>
复制代码

也可以使用Java代码获取:

//获得对数据源的引用:
Context ctx = new InitalContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/DbSource");
//获得数据库连接对象:
Connection con = ds.getConnection();
//返回数据库连接到连接池:
con.close();
复制代码

3.2.1 manager

Tomcat manager是Tomcat自带的、使用HTML界面的、管理Tomcat自身以及部署在Tomcat上的应用的web应用。

在这里插入图片描述

manager需要使用用户登陆并根据角色分配权限,角色和用户在tomcat-users.xml中配置。tomcat的tomcat-users.xml文件中默认没有配置任何用户信息:

在这里插入图片描述

tomcat-users.xml文件中的配置信息是tomcat8在server.xml中默认配置了的一个用户数据库数据源来加载的:

<!--配置全局JNDI资源-->
<GlobalNamingResources>
    <!-- 用户数据库Realm,也可以用于对用户进行身份验证的可编辑用户数据库 -->
    <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>
复制代码

该示例表示定义了一个名为UserDataBase的全局JNDI数据源,使用容器管理该Resource,该数据源为加载tomcat-users.xml文件至内存中而定义的用于用户授权的数据库。然后在认证文件tomcat-users.xml中就可以配置可以访问Manager App和Host Manager页面的用户以及权限。在Engine标签下可以通过Realm标签来引用配置的数据源,resourceName属性的值就是Resource标签的name属性值。

上面的配置中role标签用来配置角色,user标签用来配置用户。如果我们在tomcat-users.xml中添加如下配置:

在这里插入图片描述

表示登陆用户名为admin,用户密码为123456,用户权限为admin-gui和admin-script,admin-gui表示允许访问 Host Manager的html接口(即URL路径为/host-manager/html/*),admin-script表示允许访问 Host Manager的纯文本接口(即URL路径为/host-manager/text/*)。此时我们就可以访问Host Manager页面。

在这里插入图片描述

对于Manager App页面,我们则需要配置如下几个权限:

  1. manager-gui:允许访问html接口(即URL路径为/manager/html/*)。
  2. manager-script:允许访问纯文本接口(即URL路径为/manager/text/*)。
  3. manager-jmx:允许访问JMX代理接口(即URL路径为/manager/jmxproxy/*)。
  4. manager-status:允许访问Tomcat只读状态页面(即URL路径为/manager/status/*)。

manager-gui、manager-script、manager-jmx均具备manager-status的权限,也就是说,manager-gui、manager-script、manager-jmx三种角色权限无需再额外添加manager-status权限,即可直接访问路径/manager/status/*。

4 Service

包含一个Engine和多个Connector的服务组件,表示org.apache.catalina.Service接口,用于对外提供Web服务。不同的Connector接收不同的客户端请求,多个Connector共用一个Engine来处理所有Connector接收到的请求。

Server中可以包括多个Service标签,Service标签内部不能直接定义< Value/>组件。tomcat8的默认配置中包含一个名为Catalina的Service组件。

在这里插入图片描述

Service的所有实现都支持以下属性:

属性名描述
className要使用的Java实现类全路径名,指定的类必须实现org.apache.catalina.Service接口。如果未指定类名,则将使用标准实现,即org.apache.catalina.core.StandardService
nameService组件的名字,必须唯一

5 Executor

Executor即线程池执行器,一个Service中可以配置多个命名线程池,可以由其他组件共享使用,一般来说,使用线程池的是Connector组件,用于处理Http请求,要使用指定的线程池执行器,组件需要通过executor属性指定对应线程池的name属性。

为了使Connector能正常使用线程池,Executor元素应该放在Connector前面。

执行器的所有实现都支持以下属性:

属性名描述
className要使用的Java 实现类全路径名,指定的类必须实现org.apache.catalina.Executor 接口。如果未指定类名,则将使用标准实现,即org.apache.catalina.core.StandardThreadExecutor
name执行器的名字,其他组件通过名字引用该执行器,因此该属性是必需的,并且必须是唯一的

默认执行器实现支持以下属性:

属性名描述
threadPriorityExecutor内的线程的优先级,默认值为5(Thread.NORM_PRIORITY)
daemonExecutor内的线程是否是后台线程,默认值true
namePrefixExecutor创建的每个线程的名称前缀,线程池中线程名字为:namePrefix+ threadNumber
maxThreadsExecutor中最大活跃线程数,默认值200(Tomcat7和8都是) ,即处理请求的最大线程数。
minSpareThreadsExecutor中保持的最小线程数(无论是否是空闲状态),默认值是25
maxIdleTimeExecutor中空闲线程超时关闭的毫秒数(除非线程数小于或等于 minSpareThread)。默认值为 60000(1 分钟)
maxQueueSize在Executor执行拒绝策略之前,可以排队等待执行的最大可运行任务数,即任务队列的最大长度。默认值为Integer.MAX_VALUE((2147483647)
prestartminSpareThreads启动Executor时是否应立即预初始化minSpareThread线程,默认值为false
threadRenewalDelay如果配置了ThreadLocalLeakPreventionListener(默认会配置),监听器,它将通知此Executor有关的以停止的Web应用(context),停止Web应用后,池中的线程将重建。threadRenewalDelay表示重建线程的时间间隔,重建线程池内的线程时,为了避免线程同时重建,每隔threadRenewalDelay(毫秒)重建一个线程,默认值为1000,设置为负数则不重建

6 Connector

一个Connector标签代表一个与客户端实际交互的组件,负责接收客户端请求和返回响应结果。Connector标签位于Service标签下,一个Service标签可以包含多个Connector标签。

在tomcat程序中,Connector将会为每个请求创建Request和Response对象,然后分配线程让Engine(Servlet实例)来处理这个请求,并把产生的Request和Response对象传给Engine,当Engine处理完请求后,也会通过Connector将响应返回给客户端。可以说,Servlet容器处理请求,是需要Connector进行调度和控制的,Connector是Tomcat处理请求的主干之一。

我们着重要掌握连接器的属性,面试的时候经常问的tomcat的并发数量之类的都可以通过连接器设置。

连接器的所有实现都支持以下常用属性:

  1. port:连接器监听的请求端口,必须唯一。如果使用特殊值 0,则 Tomcat 将随机选择一个自由端口用于此连接器。
  2. protocol:连接器监听的请求协议类型,以及使用何种模式来接受和处理请求,默认为 HTTP/1.1类型,并且兼容HTTP1.0。tomcat6开始支持NIO,在tomcat8中增加了对NIO2的支持,tomcat8.5去除了BIO(org.apache.coyote.http11.Http11Protocol)的支持。对于HTTP协议,tomcat8中可以设置如下值:
    1. HTTP/1.1:默认值,使用的协议与Tomcat版本有关,并且会自动选取。在Tomcat7中,自动选取使用BIO或APR(如果找到APR需要的本地库,则使用APR,否则使用BIO);在Tomcat8中,自动选取使用NIO或APR(如果找到APR需要的本地库,则使用APR,否则使用NIO)。
    2. org.apache.coyote.http11.Http11NioProtocol:NIO,non blocking Java NIO connector
    3. org.apache.coyote.http11.Http11Nio2Protocol:NIO2,non blocking Java NIO2 connector
    4. org.apache.coyote.http11.Http11AprProtocol:APR,the APR/native connector.
    5. org.apache.coyote.http11.Http11Protocol:BIO,tomcat8.5已取消支持。
  3. 另外还可以设置使用AJP协议,即protocol="AJP/1.3"。AJP协议是应用在Apache在反向代理tomcat的场景,Apache和tomcat之间就是使用AJP协议通信,它是一种二进制协议。
  4. redirectPort:如果当前连接器不支持SSL(HTTPS)请求,但是收到SSL(HTTPS)请求时,Catalina将重定向至指定端口的Connector。
  5. URIEncoding:用于解码URL的字符编码,如果未指定,则默认使用 UTF-8,除非org.apache.catalina.STRICT_SERVLET_COMPLIANCE系统属性设置为 true,在这种情况下,将使用 ISO-8859-1。因此,tomcat8的get请求中的中文参数不需要再另行处理乱码问题了(此前的低版本默认是ISO8859-1)。
  6. maxPostSize:POST方法能够提交的数据的最大大小(byte)。通过将此属性设置为小于0的值,则表示不限制。如果未指定该属性,则此属性设置为 2097152(2 MB)。请注意,失败请求筛选器FailedRequestFilter可用于拒绝超过此限制的请求。
  7. enableLookups:如果要需要在调用request.getRemoteHost()时执行 DNS 查找以返回远程客户端的实际主机名,那么需要设置为 true。设置为 false 表示会跳过 DNS 查找,并且以String 形式返回 IP 地址(从而提高性能)。默认情况下为false,将禁用 DNS 查找。
  8. allowTrace:用于配置服务器能够处理用户的HAED/TRACE请求。如果未指定,则此属性设置为 false,表示不能。

除了上面的属性之外,标准 HTTP 连接器(NIO, NIO2 and APR/native)还支持下面的常见属性:

  1. connectionTimeout:此连接器在建立连接之后等待请求URI的超时时间(毫秒),使用值 -1 表示无超时时间,默认值为 60000(即 60秒)。当client与tomcat建立连接之后,在"connectionTimeout"时间之内,仍然没有得到client的请求数据,此时连接将会被断开。
  2. keepAliveTimeout:此连接器在关闭连接之前将等待另一个 HTTP 请求的超时时间(毫秒)。默认值是使用已为connectionTimeout属性设置的值,使用值 -1 表示无超时时间。
  3. maxConnections:tomcat在任何给定时间能同时接收和处理的最大连接数(不一定会被立即处理)。当Tomcat接收的连接数达到maxConnections时,Acceptor线程不会读取Accept队列中的连接;则Acceptor线程会一直阻塞着,直到Tomcat接收的连接数小于maxConnections。如果设置为-1,则连接数不受限制。
    1. 默认值因连接器类型而异。对于 NIO 和 NIO2,默认值为 10000,而BIO的默认值为maxThreads(如果配置了Executor,则默认值是Executor的maxThreads)。对于 APR/native,默认值为 8192,并且如果配置的值不是1024的倍数,maxConnections 的实际值将减少到1024的最大倍数。
  4. acceptCount:当同时连接数超过maxConnections时,系统会继续接收连接,但是传入的连接请求将在Accept等待队列等待而不会被Accepter拉取。该属性表示Accept等待队列的长度,如果等待队列也满了,那么收到的任何请求都将被直接被拒绝(返回connection refused)。默认值为100。
    1. 所以说,tomcat的可同时接收的最大连接数为maxConnections+acceptCount,对于BIO来说就是300
  5. maxThreads:每一次HTTP请求到达Web服务并建立连接之后,tomcat都会尝试创建一个线程来处理该请求。该属性表示此连接器可以创建的最大请求处理线程数,因此它决定连接器真正的可同时处理的用户请求的最大数量。如果未指定,则此属性默认设置为200。如果该Connector绑定了Executor,这个值会被忽略,因为该Connector将使用绑定的Executor,而不是内置的线程池来执行任务。
  6. executor:对 Executor 标签中name的引用。如果设置了此属性,并且存在指定的命名执行器,则该连接器将使用指定的执行器线程池,并且将忽略所有其他默认线程池属性,如果设置了默认执行器的属性,那么将报告一个-1来表示不会使用设置的属性。如果没有为连接器指定共享执行器,则连接器将使用专用的内部执行器提供线程池。
    1. 默认执行器线程命名通常是http-nio-,或者http-bio-。
  7. threadPriority:连接器的内部执行器中的请求处理线程的优先级。默认值为 5(java.lang.Thread.NORM_PRIORITY常量)。
  8. minSpareThreads:连接器的内部执行器保持的最小线程数(无论是否是空闲状态),默认值是10。
  9. SSLEnabled:设置此连接器是否开启SSL(HTTPS)的支持,如果需要开启,请将此值设置为 true。默认值为 false。将此值设置为 true 时,还需要设置scheme和secure这两个属性,即scheme="https" secure="true"。
  10. maxHttpHeaderSize:HTTP请求、响应头信息的最大大小,以字节为单位指定。如果未指定,此属性将设置为 8192 bytes(即8 KB)。

在tomcat8的默认配置中,只开放了一个Connector,其他的Connector则被注释了:

在这里插入图片描述

根据上面的属性,这个开放出来的Connector表示:客户端可以通过8080端口号使用HTTP/1.1协议(兼容HTTP1.0)访问tomcat,建立连接之后等待请求URI的超时时间为20000ms(即 20秒),并且当出现HTTPS请求时,该HTTPS请求将被转发至端口号为8443的Connector(从注释中可以看到端口号为8443的Connector设置了SSLEnabled="true",即支持处理HTTPS请求)。

http协议默认端口号为80,也就是说在URL中不给出端口号时就表示使用80端口。当然你也可以修改为其它端口号。当把端口号修改为80后,在浏览器中只需要输入:http://localhost就可以访问tomcat主页了。

7 Engine

Engine(引擎)表示一个与某个Service关联的请求处理组件,它接收并处理来自该Service中全部Connectors连接器接收到并封装的来自客户端的请求,并返回给连接器的已完成响应,以最终在通过连接器将响应传输回客户端。

Engine可以看作Servlet容器,即container。 由org.apahce.catalina.Engine接口定义。一个Service中有且只能有一个Engine组件。

Engine的所有实现都支持以下常见属性:

属性名描述
nameEngine的名称,用于日志和错误信息。在同一服务器中使用多个 Service 元素时,必须为每个Engine分配一个唯一的名称。
defaultHost默认host主机名,当发往本机的请求指定的host名称不存在或者未指定时,一律使用defaultHost指定的host进行处理,因此此名称必须与内部的一个Host标签元素的name属性匹配。
jvmRoute必须在负载平衡方案中使用的标识符,以启用session相关性。 主要是应用于tomcat集群中的session共享,会在一次会话中添加该值,获得session sticky
className指定org.apache.catalina.Engine接口的实现类全路径名,默认值为org.apache.catalina.core.StandardEngine

在tomcat8中,默认的Engine配置为:

在这里插入图片描述

8 Host

Host是Engine的子容器,Engine中可以包含1个或多个Host组件,Engine组件的defaultHost属性必须与其中一个Host的name属性一致。对应着org.apache.catalina.Host接口。

Host表示一个虚拟主机,可以包含(管理)一个或多个Web应用(Host内部的一个Context代表一个Web应用),并负责安装、展开、启动和结束每个Web应用。配置多个Host可以让一个tomcat支持从不同的域名访问Web应用。

Host 的所有实现都支持以下常见属性:

属性名描述
name虚拟主机名。一般情况下,指定主机名需要是在DNS服务器中注册的网络名。localhost是DNS服务器中已经注册好的localhost对应着127.0.0.1,因此不需要我们手动注册。 如果是本地测试,Windows系统中,可以在‪C:\Windows\System32\drivers\etc\hosts文件中添加域名映射。
appBase此虚拟主机的应用程序基础目录,这里指定目录的路径名,该目录下可能包含要在此虚拟主机上部署的 Web 应用程序。可以指定绝对路径名,也可以指定相对于tomcat基础目录的路径名。如果未指定,默认值为“webapps”。该属性主要用于Web 应用程序的自动识别和部署。
autoDeploy指示 Tomcat 在 运行时应定期检查新的或更新的 Web 应用程序。如果为true,Tomcat 会定期检查 appBase 和 xmlBase 目录,并部署找到的任何新的 Web 应用程序或上下文 XML 描述符。更新的 Web 应用程序或上下文 XML 描述符将触发 Web 应用程序的重新加载。标志的值默认为 true。有关详细信息,请参阅自动应用程序部署。
className指定org.apache.catalina.Host接口的实现类全路径名,默认值为org.apache.catalina.core.StandardHost
startStopThreads此Host主机用于并行启动/发布子Context标签(Web应用)的线程数。如果开启自动部署,那么将使用同一个线程池来部署新的Web应用。指定为0,表示将使用Runtime.getRuntime().availableProcessors()数量的线程。负值将导致使用Runtime.getRuntime().availableProcessors()+startStopThreads的线程数量,如果结果小于1,在这种情况下将使用 1 个线程。如果未指定,将使用默认1个线程,用于部署Host下的所有Web项目。如果Host下的Web项目较多,由于只有一个线程负责部署这些项目,因此这些项目将依次部署,最终导致Tomcat的启动时间较长。此时,修改startStopThreads值,增加Host部署Web项目的并行线程数,可降低Tomcat的启动时间。

Host的标准实现是org.apache.catalina.core.StandardHost,它还支持以下常见附加属性:

属性名描述
unpackWARs指示是否将代表Web应用的WAR文件解压;如果为true,则先解压然后运行解压的Web应用,如果为false,直接使用WAR文件运行Web应用。

在tomcat8中,默认的Host配置为:

在这里插入图片描述

它表示虚拟主机名为localhost,应用程序基础目录为一个相对路径,即tomcat目录下的webapps目录,并且支持自动解压应用的War包,支持自动发布和更新项目。

因此我们启动一个新的tomcat8,它的默认访问URL前缀应该是localhost:8080。

8.1 Context

Context(上下文)代表一个运行在特定虚拟主机(Host)中运行的 Web 应用程序。一个Host内可以有0个或者多个Context。

对应着org.apache.catalina.Context接口。通过配置Context标签可以手动将其他路径的Web应用配置到tomcat中。

Context的所有实现都支持以下常见属性:

  1. path
    1. 此 Web 应用程序的虚拟上下文路径。与每个请求 URI 的开头字符串匹配,用以选择适当 Web 应用程序来处理特定的URI。一个主机(Host)内的所有上下文(Context)路径必须是唯一的。比如某个context设置path=“test”,那么请求URI前缀为http://localhost:8080/test才能访问该应用内部的资源。
    2. 如果指定空字符串""的上下文路径,则表示该Context为此主机的默认的Web 应用程序,该应用程序将处理没有分配到其他上下文中的所有请求。
    3. 一个Host中应该有一个Context的path="",用于处理与任何其他上下文路径不匹配的所有请求。
  2. docBase
    1. 此web应用程序的物理根目录,若该路径是相对路径的话,则是相对于appBase而言,若是绝对路径,则与appBase无关。
    2. 比如指定某个Context的docBase =“test”,那么表示对应的web应用根目录为CATALINA_HOME/webapps/test
  3. reloadable
    1. 是否支持重新加载web应用程序类,默认为false。如果这个属性设为true,Tomcat服务器在运行时会监视在WEB-INF/classes和Web-INF/lib目录下的class文件的改变,如果监视到有class文件被,更改,服务器自重新加载该Web应用。
    2. 在开发环境下,reloadable设置为true便于调试;但是在生产环境中设置为true会给服务器带来性能压力,因此reloadable参数的默认值为false。
  4. cookies
    1. 是否通过Cookie来支持Session会话(这需要客户端支持Cookie),默认值为true。
  5. crossContext
    1. 如果要在此应用程序中调用 ServletContext.getContext()返回在此虚拟主机上运行的其他Web应用程序的请求调度程序,请设置为true。默认设置为 false,使 getContext()方法始终返回 null。
    2. 设置为true时,利用可以访问其他项目的ServletContext对象的特性,该Web项目的Session信息可以共享给同一host下的其他Web项目。
  6. className
    1. 指定org.apache.catalina.Context接口的实现类全路径名,默认值为org.apache.catalina.core.StandardContext。

上下文的标准实现是org.apache.catalina.core.StandardContext。它支持以下附加常见属性:

属性名描述
unpackWAR指示是否将代表Web应用的WAR文件解压;如果指定为true,则通过所在Host的同名unpackWAR属性确定;如果为false,则所在Host的同名unpackWAR属性将被覆盖,并且不解包,直接使用WAR文件运行Web应用。如果未指定,则默认值为 true。
useNaming指示是否支持JNDI,默认值为了true

8.2 Web应用的自动部署

tomcat可以自动部署Web应用,具体在哪里配置的呢?

我们需要配置Host组件的deployOnStartup或者autoDeploy属性。如果deployOnStartup或者autoDeploy设置为true,则tomcat启动自动部署:当检测到新的Web应用或Web应用的更新时,会触发应用的部署或重新部署。二者的主要区别在于,deployOnStartup为true时,Tomcat在启动时检查Web应用,且检测到的所有Web应用视作新应用;autoDeploy为true时,Tomcat在运行时定期检查新的Web应用或Web应用的更新。除此之外,二者的处理相似。

另外,还需要配置自动部署检查的目录,可以通过Host标签的appBase和xmlBase属性配置。appBase属性指定Web应用所在的目录,默认值是“webapps”,这是一个相对路径,代表Tomcat根目录下webapps文件夹。

xmlBase属性则是指定Web应用的XML配置文件所在的目录,默认值为conf/< engine_name>/< host_name>,例如第一部分的例子中,主机localhost的xmlBase的默认值是$TOMCAT_HOME/conf/Catalina/localhost

一个Web应用可能包括以下文件:XML配置文件,WAR包,以及一个应用目录(该目录包含Web应用的文件结构);其中XML配置文件位于xmlBase指定的目录,WAR包和应用目录位于appBase指定的目录。

Tomcat按照如下的顺序进行扫描,来检查应用更新:

  1. 扫描虚拟主机指定的xmlBase下的XML配置文件
  2. 扫描虚拟主机指定的appBase下的WAR文件
  3. 扫描虚拟主机指定的appBase下的应用目录

8.3 自动部署与Context

自动部署模式下,appBase目录中的Web应用不需要配置Context,tomcat会自动扫描appBase中的WAR包和应用目录来创建Context。 就算手动配置了Context,也不需要配置docBase和path属性。

  1. 自动部署模式下,tomcat会自动扫描appBase中的WAR包和应用目录来作为docBase属性值,如果手动指定了,返回可能会造成问题。
  2. 自动部署模式下,appBase中的Web应用不能指定path属性,path属性由配置文件的文件名、WAR文件的文件名或应用目录的名称自动推导出来。

比如,tomcat8的webapps中的默认有一下Web应用:

在这里插入图片描述

我们不必要单独为它们配置Context,它们的path就是对应的项目目录名,即docs、examples、host-manager、manager。对于名称为ROOT的目录,则该Web应用看作是虚拟主机默认的Web应用,此时path属性推导为””

因此,我们访问locahost:8080,实际上就是访问ROOT应用下的资源,而访问locahost:8080/docs,实际上就是访问docs应用下的资源。

8.4 静态部署Web应用

我们的项目默认都是放到webapps下面,此时称为自动部署,我们在学习了Context之后,现在可以将Web应用放在其他地方法,通过手动配置Context标签,也能让tomcat可以找到它,部署的应用称为外部应用。通过Context部署的项目称为静态部署。

假设有一个Web应用目录为G:\work\hello,这时我们需要通过tomcat访问,那么我们可以在Server.xml中配置Context标签:

<Context docBase="G:\work\hello" path="" reloadable="true" />
复制代码

reloadable属性的用法与自动部署时相同。静态部署时,也可以显式指定path属性,但是仍然受到了严格的限制:只有当自动部署完全关闭(deployOnStartup和autoDeploy都为false)或docBase不在appBase中时,才可以设置path属性。

还有一种方法,在conf/catalana/localhost目录下创建一个hello.xml文件,在该文件中编写< Context/>标签,在标签中指明Web目录地址。

<Context docBase="G:\work\hello"/>	
复制代码

此时path属性自动推导。

9 tomcat的请求查找流程

当请求被发送到Tomcat所在的主机时,如有多个Web应用,如何确定最终哪个Web应用来处理该请求呢?大概流程图如下:

在这里插入图片描述

其中index.html表示hello应用中的静态资源路径,通过该路径可以直接访问静态资源,而servlet/Aservlet则表示hi应用中的动态资源Servlet的映射路径,通过该路径可以找到对应的Servlet,随后即可处理请求。

9.1 根据协议和端口号选定Service和Engine

Service中的Connector组件可以接收特定端口和特定类型的请求,因此,当Tomcat启动时,Service组件就会监听特定的端口。当请求进来时,Tomcat便可以根据协议和端口号选定处理请求的Service;Service一旦选定,Engine也就确定。

tomcat8默认的Service配置监听8080端口的HTTP请求。

通过在Service中配置多个Connector或者在Server中配置多个Service,可以实现通过不同的端口号来访问同一台机器上部署的不同应用。

9.2 根据域名或IP地址选定Host

Service确定后,Tomcat在Service内部的Engine中寻找name属性值与域名/IP地址匹配的Host处理该请求。如果没有找到,则使用Engine中指定的defaultHost来处理该请求。

tomcat8默认的Engine内部只有一个Host,name为locathost,并且defaultHost属性为locathost,因此该Service的所有请求都交给该Host处理。

9.3 根据URI选定Context(Web应用)

选定Host之后,用于处理每个 HTTP 请求的 Web 应用程序由 Catalina 根据将请求 URI 的最长前缀与每个Context的上下文路径path来匹配,如果与某个Context的path一致,那么表示该请求将选择该Context对应的Web应用程序来处理,如果没有与任何一个Context的path匹配成功,那么将使用path=""的Conext。

在选择Context后,该上下文将根据对应的 Web 应用程序在部署时指定的 servlet 映射路径,选择适当的 servlet 来处理传入请求。

参考资料:

  1. Apache Tomcat 8 Configuration Reference
  2. 深入理解-Tomcat-(二)-从宏观上理解-Tomcat-组件及架构
  3. 深度解读Tomcat中的NIO模型
  4. 详解tomcat的连接数与线程池

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

分类:
后端
分类:
后端
收藏成功!
已添加到「」, 点击更改