Tomcat基本架构解析(Tomcat架构解析学习笔记)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_26323323/article/details/84848305

1.Tomcat组件架构设计

    1)server

        服务器可以描述为这样一个应用:接收客户端发来的请求数据并进行解析,完成相关业务处理,然后把处理结果作为相应返回给客户端。

        通常我们可以使用serversocket监听指定端口来实现该功能

    2)Connection和Container(Engine)

        当我们将请求监听和请求处理放在一起的时候扩展性就很差。比如当我们想适配多种网络协议,但是请求处理却相同的时候。

        处理方案就是:将网络协议和请求处理从概念上分开。Connection负责开启socket并监听客户端请求、返回响应数据;Container(Engine)负责具体的请求处理。

    3)Service

        上述方案的缺陷就是无法很好的判断Connection由哪个Container(Engine)来处理。

        采用service方案,一个server包含多个service(它们相互独立),一个service包含多个Connection和一个Container,这样,connection的请求只能由该container来处理

        由于Container表示一个更加通用的概念,为了与Tomcat组件命名一致,将Container重新命名为Engine,用于表示整个servlet引擎

    4)Context

        上述解决了网络协议和容器的解耦。下面我们需要在Engine中支持管理web应用。当接收到Connection请求时,能够找到一个合适的Web应用来处理。Context就代表一个Web应用

    5)Host

        为了提供对多个域名的服务,我们可以将每个域名视为一个虚拟的主机。在每个Host下包含多个Context

       

    6)Wrapper

        在一个Web应用中,可以包含多个servlet实例来处理不同链接的请求。因此,需要一个组件概念来表示Servlet定义,在Tomcat中servlet定义被称为Wrapper

    7)Container

        容器代表一类组件,这类组件的作用就是接收客户端请求并返回响应数据,具体操作委派到子组件完成。

        Engine、Host、Context、Wrapper均继承自Container

    8)LifeCycle

        所有的组件均存在启动、停止等生命周期方法,拥有生命周期管理的特性,我们将这个抽取出来作为接口LifeCycle,定义生命周期管理的核心方法。

    9)Executor

        tomcat的并发,提供了Executor接口来表示一个可以在组件间共享的线程池。该接口同样继承LifeCycle接口

        共享范围:Executor由Service维护,因此同一个Service中的组件可以共享一个线程池

        

    10)Bootstrap和Catalina

        Catalina提供一个shell程序,用于解析service.xml创建各个组件。同时负责启动、停止应用服务器

        Bootstrap作为应用服务器启动入口。Bootstrap负责创建Catalina,根据执行参数调用Catalina相关方方法完成对应用服务器的操作

    总结:

        * Server 表示整个servlet容器,因此Tomcat容器中只有一个Server实例

        * Service 表示一个或多个Connector的集合。这些Connector共享同一个Container来处理其他请求。在一个Server中可以包含多个Service,这些Service相互独立

        * Connector Tomcat连接器,用于监听并转换为Socket请求,将该请求交由Container处理,支持不同的协议及不同IO方式

        * Container 表示能够接收请求并返回响应的一类对象。在Tomcat中存在不同级别的容器:Engine、Host、Context、Wrapper

        * Engine 表示整个Servlet引擎,Engine为最高级别的容器。尽量Engine不是直接处理请求的容器却是获得目标容器的入口

        * Host 表示Engine中的虚拟机,与一个服务器的网络名有关,如域名等。客户端可以使用这个网络名连接服务器,这个名称必须要在DNS服务器上注册

        * Context 用于表示ServletContext,在Servlet规范中,一个ServletContext表示一个Web应用

        * Wrapper 表示Web应用中定义的Servlet

        * Executor 表示Tomcat组件间可以共享的线程池

2.请求处理过程

    从本质上讲,应用服务器的处理开始于监听的Socket端口接收到数据,结束于将处理结果写入Socket输出流

    * 应用服务器将请求按照既定协议进行读取,并将其封装为与具体协议无关的请求体

    * 按照请求映射规则将请求定位到具体的处理单元(使用框架的话SpringMVC等则会将请求匹配到Servlet下的一个控制器)

    * 业务处理结束,将结果封装到一个与协议无关的响应对象

3.Tomcat类加载方案

    应用服务器通常会创建类加载器以实现更灵活的控制。

    * 隔离性:Web应用类库互相隔离,避免依赖库或应用包相互影响。设想有两个应用,一个采取Spring2.X,一个采取Spring4.X,而应用服务器使用同一个类加载器,那么应用之间会因为jar包覆盖导致无法启动

    * 灵活性:Web应用之间的类加载器相互独立,我们就能只针对一个Web应用重新部署

    * 性能:每个Web应用都有一个类加载器,则Web应用在加载类时,不会搜索其他Web应用包含的jar包,性能自然高

    1)Common 位于Tomcat顶层的公共类加载器,默认指向Tomcat_home/lib下的包

    2)Catalina 用于加载Tomcat应用服务器的类加载器,路径为server.loader,默认为空

    3)Shared 所有web应用的父加载器,路径为shared.loader,默认为空

    4)Web 加载WEB-INF/classes下的未压缩的class、资源文件及WEB-INFO/lib下的jar包,该类加载器只对当前web应用可见

    在catalina.jar org.apache.catalina.loader包下可以看到关于ClassLoader的实现

4.通过server.xml来查看Tomcat各组件之间的关系

    我们在Eclipse中创建一个web项目,springweb,并在Eclipse中关联Tomcat8.5,并在Tomcat中关联springweb,启动Tomcat,可以看到生成的server.xml如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<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 SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>
  <!-- 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"/>

  
  <GlobalNamingResources>
   
    <Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
  </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">
    <!-- 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 connectionTimeout="20000" port="8080" protocol="HTTP/1.1" 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 defaultHost="localhost" name="Catalina">
      <!-- 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 appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="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" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log" suffix=".txt"/>

      <Context docBase="springweb" path="/springweb" reloadable="true" source="org.eclipse.jst.jee.server:springweb"/></Host>
    </Engine>
  </Service>
</Server>

    由上可知,Tomcat结构图可如下所示:

    * Tomcat只要一个Server,一个Server可以有多个Service,一个Service可以有多个Connection和Container

    * Server掌管整个Tomcat的生死大权

    * Service是对外提供服务的

    * Connector用于接收请求并将请求封装成Request和Response来具体处理

    * Container用于管理和封装Servlet,以及处理具体Request请求

参考:Tomcat架构解析(刘光瑞)

猜你喜欢

转载自blog.csdn.net/qq_26323323/article/details/84848305