体系结构简图
核心配置文件
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
<Listener className="org.apache.catalina.core.JasperListener" />
<!-- 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>
<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">
<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 "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
由上面的结构图和配置文件可以看出tomcat 基本组件构成为Server、Service、Connector、Engine、Host、Context、Wrapper
它们的基本功能如下
- server组件是管理tomcat实例的组件,可以监听一个端口,从此端口上可以远程向该实例发送shutdown关闭命令。
- service组件是一个逻辑组件,用于绑定connector和container,有了service表示可以向外提供服务,就像是一般的daemon类服务的service。可以认为一个service就启动一个JVM,更严格地说,一个engine组件才对应一个JVM(定义负载均衡时,jvmRoute就定义在Engine组件上用来标识这个JVM),只不过connector也工作在JVM中。
- connector组件是监听组件,它有四个作用:
(1). 开启监听套接字,监听外界请求,并和客户端建立TCP连接;
(2). 使用protocolHandler解析请求中的协议和端口等信息,如http协议、AJP协议;
(3). 根据解析到的信息,使用processer将分析后的请求转发给绑定的Engine;
(4). 接收响应数据并返回给客户端。 - container是容器,它是一类组件,在配置文件(如server.xml)中没有体现出来。它包含4个容器类组件:engine容器、host容器、context容器和wrapper容器。
- engine容器用于从connector组件处接收已建立的TCP连接,还用于接收客户端发送的http请求并分析请求,然后按照分析的结果将相关参数传递给匹配出的虚拟主机。engine还用于指定默认的虚拟主机。
- host容器定义虚拟主机,由于tomcat主要是作为servlet容器的,所以为每个webapp指定了它们的根目录appBase。
- context容器主要是根据path和docBase获取一些信息,将结果交给其内的wrapper组件进行处理(它提供wrapper运行的环境,所以它叫上下文context)。一般来说,都采用默认的标准wrapper类,因此在context容器中几乎不会出现wrapper组件。
- wrapper容器对应servlet的处理过程。它开启servlet的生命周期,根据context给出的信息以及解析web.xml中的映射关系,负责装载相关的类,初始化servlet对象init()、执行servlet代码service()以及服务结束时servlet对象的销毁destory()。
- executor组件为每个Service组件提供线程池,使得各个connector和Engine可以从线程池中获取线程处理请求,从而实现tomcat的并发处理能力。一定要注意,Executor的线程池大小是为Engine组件设置,而不是为Connector设置的,Connector的线程数量由Connector组件的acceptorThreadCount属性来设置。如果要在配置文件中设置该组件,则必须设置在Connector组件的前面,以便在Connector组件中使用
executor
属性来引用配置好的Executor组件。如果不显式设置,则采用Connector组件上的默认配置,默认配置如下:
(1). maxThreads:最大线程数,默认值200。
(2). minSpareThreads:最小空闲线程数,默认值25。
(3). maxIdleTime:空闲线程的线程空闲多长时间才会销毁,默认值60000即1分钟。
(4). prestartminSpareThreads:是否启动executor时就直接创建等于最小空闲线程数的线程,默认值为false,即只在有连接请求进入时才会创建。
- 总结起来:Tomcat 就两个核心组件连接器(Connector)和容器(Container)
- 连接器,负责对外交流: 处理Socket连接,负责⽹络字节流与Request和Response对象的转化;
- 容器,负责内部处理:加载和管理Servlet,以及具体处理Request请求,大概可以描述为如下流程
- Client(request)–>Connector–>Engine–>Host–>Context–>Wrapper(response data)–>Connector(response header)–>Client
Tomcat 连接器组件 Coyote
Coyote 是Tomcat 中连接器的组件名称 , 是对外的接口。客户端通过Coyote与服务器建立连接、发送请 求并接受响应 ,主要有如下功能
- 封装了底层的网络通信(Socket 请求及响应处理)
- 使Catalina 容器(容器组件)与具体的请求协议及IO操作方式完全解耦
- 将Socket 输入转换封装为 Request 对象,进一步封装后交由Catalina 容器进行处理,处理请求完成后, Catalina 通过Coyote 提供的Response 对象将结果写入输出流
- 负责的是具体协议(应用层)和IO(传输层)相关内容
- Tomcat Coyote 支持的 IO模型与协议,如下
在 8.0 之前 ,Tomcat 默认采用的I/O方式为 BIO,之后改为 NIO。 无论 NIO、NIO2 还是 APR, 在性 能方面均优于以往的BIO。 如果采用APR, 甚至可以达到 Apache HTTP Server 的影响性能。
- Coyote 的内部组件及流程
- Coyote 组件及作用
组件 | 作用描述 |
---|---|
EndPoint | EndPoint 是 Coyote 通信端点,即通信监听的接口,是具体Socket接收和发 送处理器,是对传输层的抽象,因此EndPoint用来实现TCP/IP协议的 |
Processor | Processor 是Coyote 协议处理接口 ,如果说EndPoint是用来实现TCP/IP协 议的,那么Processor用来实现HTTP协议,Processor接收来自EndPoint的 Socket,读取字节流解析成Tomcat Request和Response对象,并通过 Adapter将其提交到容器处理,Processor是对应用层协议的抽象 |
ProtocolHandler | Coyote 协议接口, 通过Endpoint 和 Processor , 实现针对具体协议的处 理能力。Tomcat 按照协议和I/O 提供了6个实现类 : AjpNioProtocol , AjpAprProtocol, AjpNio2Protocol , Http11NioProtocol , Http11Nio2Protocol ,Http11AprProtocol |
Adapter | 由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat定义了自己的 Request类来封装这些请求信息。ProtocolHandler接口负责解析请求并生成 Tomcat Request类。但是这个Request对象不是标准的ServletRequest,不 能用Tomcat Request作为参数来调用容器。Tomcat设计者的解决方案是引 入CoyoteAdapter,这是适配器模式的经典运用,连接器调用 CoyoteAdapter的Sevice方法,传入的是Tomcat Request对象, CoyoteAdapter负责将Tomcat Request转成ServletRequest,再调用容器 |
Tomcat Servlet 容器 Catalina
Tomcat是一个由一系列可配置(conf/server.xml)的组件构成的Web容器,而Catalina是Tomcat的 servlet容器。
从另一个⻆度来说,Tomcat 本质上就是一款 Servlet 容器, 因为 Catalina 才是 Tomcat 的核心 , 其 他模块都是为Catalina 提供支撑的。 比如 : 通过 Coyote 模块提供链接通信,Jasper 模块提供 JSP 引 擎,Naming 提供JNDI 服务,Juli 提供日志服务。
-
Servlet 容器 Catalina 的结构,下图跟最上面的结构图内容一样,更简洁明了
-
可以认为整个Tomcat就是一个Catalina实例,Tomcat 启动的时候会初始化这个实例,Catalina 实例通过加载server.xml完成其他实例的创建,创建并管理一个Server,Server创建并管理多个服务, 每个服务又可以有多个Connector和一个Container。
-
一个Catalina实例对应一个 Server实例,一个 Server实例对应多个Service实例,每一个Service实例下可以有多个Connector实例和一个Container实例
- Catalina
负责解析Tomcat的配置文件(server.xml) , 以此来创建服务器Server组件并进行管理- Server
服务器表示整个Catalina Servlet容器以及其它组件,负责组装并启动Servlaet引擎,Tomcat连接 器。Server通过实现Lifecycle接口,提供了一种优雅的启动和关闭整个系统的方式- Service
服务是Server内部的组件,一个Server包含多个Service。它将若干个Connector组件绑定到一个 Container- Container
容器,负责处理用户的servlet请求,并返回对象给web用户的模块
- Container 组件的具体结构
Container组件下有几种具体的组件,分别是Engine、Host、Context和Wrapper。这4种组件(容器)是父子关系。
Tomcat通过一种分层的架构,使得Servlet容器具有很好的灵活性。
- Engine
表示整个Catalina的Servlet引擎,用来管理多个虚拟站点,一个Service最多只能有一个Engine, 但是一个引擎可包含多个Host- Host
代表一个虚拟主机,或者说一个站点,可以给Tomcat配置多个虚拟主机地址,而一个虚拟主机下可包含多个Context- Context
表示一个Web应用程序, 一个Web应用可包含多个Wrapper- Wrapper
表示一个Servlet,Wrapper 作为容器中的最底层,不能包含子容器