Tomcat结构及类加载机制

一、Tomcat接口

server.xml配置文件讲解

<?xml version='1.0' encoding='utf-8'?>
<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.JasperListener" />
  <Listener  className="org.apache.catalina.core.JreMemoryLeakPreventionListener"  />
  <Listener  className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"  />
  <Listener  className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"  />
  <GlobalNamingResources>     <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 name="Catalina">
    <!--两个链接,不同协议不同端口号-->
    <Connector port="8080" protocol="HTTP/1.1"           connectionTimeout="20000"           redirectPort="8443" />     <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
    <Engine name="Catalina" defaultHost="localhost">       <Realm className="org.apache.catalina.realm.LockOutRealm">       <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
           resourceName="UserDatabase"/>       </Realm>
      <!--webapps对应着文件夹webapps项目部署-->       
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">         <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.xml图示

server.xml模型图:

  Tomcat中最顶层的容器是Server,代表着整个服务器,从上图中可以看出,一个Server可以包含至少一个Service,用于具体提供服务。
 
  Service主要包含两个部分:多个Connector和一个Container。一个Container可以有多个Host(虚拟主机),一个Host可以有多个Context。从上图中可以看出 Tomcat 的心脏就是这两个组件,他们的作用如下:
  1、Connector用于处理连接相关的事情,并提供Socket与Request和Response相关的转化;
  2、Container用于封装和管理Servlet,以及具体处理Request请求
 
  一个Service只有一个Container,但是可以有多个Connectors。因为一个服务可以有多个连接,如同时提供Http和Https链接,也可以提供向相同协议不同端口的连接。

Tomcat架构小结(面试回答这个):
  [1]每一个tomcat都只有一个Server,表示整个服务环境。一个Server中可以有多个Service。Server就掌管着Service的死活。
  [2]Service是对外提供服务的,每一个Service中可以有多个Connector和一个Container(Engine)。
  [3]Connector主要用来接收请求,解析请求内容,封装request和response,然后将准备好的数据交给Container处理。
  [4]Container就是我们经常说的容器,里面可以有多个Host,一个Host表示一个虚拟主机。Container处理完请求之后会将响应内容返回给Connecter,再由Connecter响应客户端。
 
面试进阶——Connector架构
  Connector的架构: Connector最底层使用的是Socket来进行连接的,Request和Response是按照HTTP协议来封装的,所以Connector同时需要实现TCP/IP协议和HTTP协议!
 

  [1] Connector中具体用ProtocolHandler来处理请求的,不同的ProtocolHandler代表不同的连接类型(如 Http11Protocol使用普通的Socket来连接,Http11NioProtocol使用NioSocket连接)。

  [2] Endpoint用于处理底层Socket的网络连接,用来实现TCP/IP协议 。

    Acceptor:用于监听和接受请求。 

    Handler:请求的初步处理。并且调用Processor。 

    AsyncTimeout:检查异步的Request请求是否超时。

  [3] Processor用于将Endpoint接收到的Socket封装成Request,用来实现HTTP协议。

  [4] Adapter用于将Request交给Container进行具体处理,即将请求适配到Servlet容器。

面试进阶——Container架构:  

  Container就是一个Engine。Container用于封装和管理Servlet,以及具体处理Request请求。

  [1] Engine:Container(容器/引擎),用来管理多个站点,一个Service最多只能有一个Engine.

  [2] Host: 虚拟主机,一个Container可以有多个虚拟主机。

  [3] Context: 一个应用程序,就是我们平时开发的一个项目,或者说一套web引用程序。

  [4] Wrapper:  用来包装Servlet,每一个Wraper都包装着一个Servlet。

二、类加载器流程

  JVM类加载机制:详情

    Tomcat类加载:

JVM类加载机制

  Bootstrap 引导类加载器 :加载JVM启动所需的类,以及标准扩展类(位于jre/lib/ext下),将JVM前三个类加载器概括到一起了。

  System 系统类加载器 :加载tomcat启动的类,比如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin下。

   Common 通用类加载器:加载tomcat使用以及应用通用的一些类,位于CATALINA_HOME/lib下,比如servlet-api.jar。

  webapp应用类加载器:每个应用在部署后,都会创建一个唯一的类加载器。该类加载器会加载位于 WEB-INF/lib下的jar文件中的class和 WEB-INF/classes下的class文件。

  JSP类加载器 :tomcat会为每一个JSP创建一个类加载器。

加载流程

  1  使用bootstrap引导类加载器加载 JVM基本类和扩展类

  2  使用system系统类加载器加载 tomcat启动的类

  3  使用应用类加载器在WEB-INF/classes中加载

  4 使用应用类加载器在WEB-INF/lib中加载

  5 使用common类加载器在CATALINA_HOME/lib中加载

问题1:为什么tomcat要给每个应用设置一个独立的类加载器

  一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一 个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。例如项目1使用spring5.0,项目2使用spring5.1,两项目具有相同的类,当项目1进行了加载之后,项目二如果发现类已经加载过了就不会再进行加载。

问题2:为什么要给每个jsp文件设置一个独立的类加载器

  web容器要支持jsp的修改,我们知道,jsp文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情。 所以,web容器需要支持 jsp 修改后不用重启。

问题3:tomcat是否违背了双亲委派模型

   是的,违背了。tomcat 为了实现隔离性,没有遵守这个约定,每个webappClassLoader加载自己的目录下的class 文件,不会传递给父类加载器。

原文地址:https://www.cnblogs.com/qmillet/p/12552336.html