Tomcat 架构简介

博客地址
https://javaedge.blog.csdn.net/

Tomcat除了能支撑通常的web app,其本身高度模块化的架构,也带来了最大限度的可扩展性。

目前tomcat版本已经衍生到tomcat9

本文以tomcat9为基础

Tomcat是有一系列逻辑模块组织而成,这些模块主要包括:

  • 核心架构模块,例如Server,Service,engine,host和context及wrapper等
  • 网络接口模块connector
  • log模块
  • session管理模块
  • jasper模块
  • naming模块
  • JMX模块
  • 权限控制模块
  • ……

本文以介绍核心架构模块为主。

1 核心架构模块说明

核心架构模块之间是层层包含关系。

例如可以说Service是Server的子组件,Server是Service的父组件。
server.xml已经非常清晰的定义了这些组件之间的关系及配置。

Service中配置了实际工作的Engine,同时配置了用来处理时间业务的线程组Executor(如果没有配置则用系统默认的WorkThread模式的线程组),以及处理网络socket的相关组件connector。

  • 1:n代表一对多的关系;1:1代表一对一的关系

    StandEngine, StandHost, StandContextStandWrapper是容器,他们之间有互相的包含关系。
    例如,StandEngineStandHost的父容器,StandHostStandEngine的子容器。在StandService内还包含一个ExecutorConnector
  • Executor是线程池,它的具体实现是executor,这个不是必须的,如果没有配置,则使用自写的worker thread线程池
  • Connector是网络socket相关接口模块,它包含两个对象,ProtocolHandler及Adapter
    • ProtocolHandler是接收socket请求,并将其解析成HTTP请求对象,可以配置成nio模式或者传统io模式
    • Adapter是处理HTTP请求对象,它就是从StandEngine的valve一直调用到StandWrapper的valve

2 分层建模

一个服务器无非是接受HTTP request,然后处理,产生HTTP response通过原有连接返回给客户端。
那为什么会整出这么多的模块进行处理,这些模块是不是有些多余呢?

其实这些模块各司其职,我们从底层wrapper开始,一直到顶层的server

通过这些描述,会发现这正是tomcat架构的高度模块化的体现。这些细分的模块,使得tomcat非常健壮,通过一些配置和模块定制化,可以很大限度的扩展tomcat。

首先,我们以一个典型的页面访问为例,假设访问的URL是
http://www.mydomain.com/app/index.html

  • Wrapper封装了具体的访问资源 index.html
  • Context 封装了各个wrapper资源的集合 app
  • Host 封装了各个context资源的集合 www.mydomain.com

按照领域模型,这个典型的URL访问,可以解析出三层领域对象,他们之间互有隶属关系。这是最基本的建模。
从上面的分析可以看出,从wrapperhost层层递进,层层组合。
那么host 资源的集合是什么呢,就是上面所说的engine
如果说以上的三个容器可以看成是物理模型的封装,那么engine可以看成是一种逻辑的封装。

有这套engine的支持,我们已经可以完成从enginehostcontext再到某个特定wrapper的定位,然后进行业务逻辑的处理

先说线程池,这是典型的线程池的应用。首先从线程池中取出一个可用线程,来处理请求,这个组件就是connector
它就像酒店的前台服务员登记客人信息办理入住一样,主要完成了HTTP消息的解析,根据tomcat内部的mapping规则,完成从enginehostcontext再到某个特定wrapper的定位,进行业务处理,然后将返回结果返回。之后,此次处理结束,线程重新回到线程池中,为下一次请求提供服务。

如果线程池中没有空闲线程,则请求被阻塞,直到有空闲线程进行处理,最多至阻塞超时。
线程池的实现有executorworker thread(默认)

至此,可以说一个酒店有了前台接待,有了房间等硬件设施,就可以开始正式运营了。

那么把engine,处理线程池,connector封装在一起,形成了一个完整独立的处理单元,这就是service,就好比某个独立的酒店。

通常,我们经常看见某某集团旗下酒店。也就是说,每个品牌有多个酒店同时运营。就好比tomcat中有多个service独自运行。那么这多个service的集合就是server,就好比是酒店所属的集团。

3 作用域

按层次分别封装一个对象主要是为了方便统一管理。

类似命名空间的概念,在不同层次的配置,其作用域不一样。

以tomcat自带的打印request与response消息的RequestDumperValve为例。这个valve的类路径
org.apache.catalina.valves.RequestDumperValve

valve机制是tomcat非常重要的处理逻辑的机制
如果这个valve配置在server.xml的节点下,则其只打印出访问这个app(my)的request与response消息。

<Host name="localhost" appBase="webapps"  
          unpackWARs="true" autoDeploy="true"  
          xmlValidation="false" xmlNamespaceAware="false">  
             <Context path="/my" docBase=" /usr/local/tomcat/backup/my" >  
                   <Valve className="org.apache.catalina.valves.RequestDumperValve"/>  
             </Context>  
             <Context path="/my2" docBase=" /usr/local/tomcat/backup/my" >  
             </Context>  
  </Host> 

若这个valve配置在server.xml节点下,则可以打印出访问这个host下两个apprequestresponse信息

<Host name="localhost" appBase="webapps"  
                unpackWARs="true" autoDeploy="true"  
                xmlValidation="false" xmlNamespaceAware="false">  
                    <Valve className="org.apache.catalina.valves.RequestDumperValve"/>  
                    <Context path="/my" docBase=" /usr/local/tomcat/backup/my" >  
                    </Context>  
                    <Context path="/my2" docBase=" /usr/local/tomcat/backup/my" >   
                    </Context>  
  </Host> 

在这里贴一个默认的server.xml的配置,通过这些配置可以加深对tomcat核心架构分层模块的理解

<!-- 注意:“Server”本身不是“Container”,因此不能在此级别定义子组件,例如“Valves”。
     文档位于/docs/config/server.html
 -->
<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 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" />

  <!-- JNDI 全局资源
      文档在/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>

  <!-- “Service”是一个或多个共享单个“Container”的“Connectors”的集合
       注意:“Service”本身不是“容器”,因此不能在此级别定义子组件,例如“Valves”。
       D/docs/config/service.html
   -->
  <Service name="Catalina">

    <!--The connectors can use a shared executor, you can define one or more named thread pools-->
    <!--
    <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
         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 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" />
    -->
    <!-- 在端口8443上定义SSL / TLS HTTP / 1.1连接器
         该连接器使用NIO实现。 
         默认的SSLImplementation将取决于APR /本地库的存在以及AprLifecycleListener的useOpenSSL属性。
         无论选择了哪种SSLImplementation,都可以使用JSSE或OpenSSL样式配置。 下面使用JSSE样式配置。
    -->
    <!--
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true">
        <SSLHostConfig>
            <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>
    -->
    <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
         This connector uses the APR/native implementation which always uses
         OpenSSL for TLS.
         Either JSSE or OpenSSL style configuration may be used. OpenSSL style
         configuration is used below.
    -->
    <!--
    <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>
    -->

    <!-- 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">

      <!--For clustering, please take a look at documentation at:
          /docs/cluster-howto.html  (simple how to)
          /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 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">

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

      </Host>
    </Engine>
  </Service>
</Server>
#Proto#
全部评论

相关推荐

1 10 评论
分享
牛客网
牛客企业服务