0%

Tomcat框架介绍

Tomcat架构

Http请求处理

image-20200814053746311

图1,表示HTTP服务器直接调用具体业务类,它们是紧耦合的。
图2,HTTP服务器不直接调用业务类,而是把请求交给容器来处理,容器通过Servlet接口调用业务类。

因此Servlet接口和Servlet容器的出现,达到了HTTP服务器与业务类解耦的目的,Tomcat按照Servlet规范的要求实现了Servlet容器,同时它们也具有HTTP服务器的功能。

作为Java程序员,如果我们要实现新的业务功能,只需要实现一个Servlet,并把它注册到Tomcat(Servlet容器)中,剩下的事情就由Tomcat帮我们处理了。

Servlet容器工作流程

为了解耦,HTTP服务器不直接调用Servlet,而是把请求交给Servlet容器来处理

image-20200819094413866

Tomcat整体架构

我们知道如果要设计一个系统,首先是要了解需求,我们已经了解了Tomcat要实现两个核心功能:
1) 处理Socket连接,负责网络字节流与Request和Response对象的转化。
2) 加载和管理Servlet,以及具体处理Request请求。
因此Tomcat设计了两个核心组件连接器(Connector)和容器(Container)来分别做这两件事情。连接器负责对外交流,容器负责内部处理。

image-20200819094629166

连接器 - Coyote

架构介绍

Coyote 是Tomcat的连接器框架的名称 , 是Tomcat服务器提供的供客户端访问的外部接口。

客户端通过Coyote与服务器建立连接、发送请求并接受响应 。

Coyote 封装了底层的网络通信(Socket 请求及响应处理),为Catalina 容器提供了统一的接口,使Catalina 容器与具体的请求协议及IO操作方式完全解耦。

Coyote 将Socket 输入转换封装为 Request 对象,交由Catalina 容器进行处理,处理请求完成后, Catalina 通过Coyote 提供的Response 对象将结果写入输出流 。

Coyote 作为独立的模块,只负责具体协议和IO的相关操作, 与Servlet 规范实现没有直接关系,因此即便是 Request 和 Response 对象也并未实现Servlet规范对应的接口, 而是在Catalina 中将他们进一步封装为ServletRequest 和 ServletResponse

image-20200819095016265

IO 模型与协议

在Coyote中 , Tomcat支持的多种I/O模型和应用层协议,具体包含哪些IO模型和应用层协议,请看下表:
Tomcat 支持的IO模型(自8.5/9.0 版本起,Tomcat 移除了 对 BIO 的支持):

IO 模型 描述
NIO 非阻塞I/O,采用Java NIO类库实现
NIO2 异步I/O,采用JDK 7最新的NIO2类库实现。
APR 采用Apache可移植运行库实现,是C/C++编写的本地库。如果选择该方
案,需要单独安装APR库。

Tomcat 支持的应用层协议 :
| IO 模型 | 描述 |
| ——– | ———————————————————— |
| HTTP/1.1 | 这是大部分Web应用采用的访问协议。 |
| AJP | 用于和Web服务器集成(如Apache),以实现对静态资源的优化以及
集群部署,当前支持AJP/1.3。 |
| HTTP/2 | HTTP 2.0大幅度的提升了Web性能。下一代HTTP协议 , 自8.5以及9.0
版本之后支持。 |

在 8.0 之前 , Tomcat 默认采用的I/O方式为 BIO , 之后改为 NIO。 无论 NIO、NIO2还是 APR, 在性能方面均优于以往的BIO。 如果采用APR, 甚至可以达到 Apache HTTPServer 的影响性能。

连接器组件

image-20200819095912251

连接器中的各个组件的作用如下:

EndPoint

1) EndPoint : Coyote 通信端点,即通信监听的接口,是具体Socket接收和发送处理器,是对传输层的抽象,因此EndPoint用来实现TCP/IP协议的。

2) Tomcat 并没有EndPoint 接口,而是提供了一个抽象类AbstractEndpoint , 里面定义了两个内部类:Acceptor和SocketProcessor。

  • Acceptor用于监听Socket连接请求。

  • SocketProcessor用于处理接收到的Socket请求,它实现Runnable接口,在Run方法里调用协议处理组件Processor进行处理。为了提高处理能力,SocketProcessor被提交到线程池来执行。而这个线程池叫作执行器(Executor)

Processor

Processor : Coyote 协议处理接口 ,Processor接收来自EndPoint的Socket,读取字节流解析成Tomcat Request和Response对象,并通过Adapter将其提交到容器处理

ProtocolHandler

ProtocolHandler : Coyote 协议接口, 通过Endpoint 和 Processor , 实现针对具体协议的处理能力。

Tomcat 按照协议和I/O 提供了6个实现类 : AjpNioProtocol ,AjpAprProtocol, AjpNio2Protocol , Http11NioProtocol ,Http11Nio2Protocol ,Http11AprProtocol。

我们在配置tomcat/conf/server.xml 时 , 至少要指定具体的ProtocolHandler , 当然也可以指定协议名称 , 如 : HTTP/1.1

Adapter

由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat定义了自己的Request类来“存放”这些请求信息。ProtocolHandler接口负责解析请求并生成Tomcat Request类。但是这个Request对象不是标准的ServletRequest,也就意味着,不能用Tomcat Request作为参数来调用容器。

Tomcat设计者的解决方案是引入CoyoteAdapter,这是适配器模式的经典运用,连接器调用CoyoteAdapter的Sevice方法,传入的是TomcatRequest对象,CoyoteAdapter负责将Tomcat Request转成ServletRequest,再调用容器的Service方法

Container结构

Tomcat设计了4种容器,分别是Engine、Host、Context和Wrapper。这4种容器不是平行关系,而是父子关系。, Tomcat通过一种分层的架构,使得Servlet容器具有很好的灵活性

image-20200819101901372

容器 描述
Engine 标识整个Catalina的servlet引擎,用来管理多个虚拟站点,一个Service只能有一个Engine,但是可以有多个Host
Host 一个虚拟主机,或者说一个站点,可以给Tomcat配置多个虚拟主机地址,而一个虚拟主机下可包含多个Context
Context 表示一个Web应用程序,一个Context包含多个Wrapper
Wrapper 一个Wrapper标识一个Servlet
1
2
3
4
5
6
7
8
9
<Server>
<Service>
<Connector/>
<Connector/>
<Engine>
<Host></Host>
</Engine>
</Service>
</Server>

所有容器组件都实现了Container接口,因此组合模式可以使得用户对单容器对象和组合容器对象的使用具有一致性。这里单容器对象指的是最底层的Wrapper,组合容器对象指的是上面的Context、Host或者Engine。

Container

启动流程

image-20200820151909025

1.启动tomcat , 需要调用 bin/startup.bat (在linux 目录下 , 需要调用 bin/startup.sh) 在startup.bat 脚本中, 调用了catalina.bat。

2.在catalina.bat 脚本文件中,调用了BootStrap 中的main方法。

3.在BootStrap 的main 方法中调用了 init 方法 , 来创建Catalina 及 初始化类加载器。

4.在BootStrap 的main 方法中调用了 load 方法 , 在其中又调用了Catalina的load方法。

5.在Catalina 的load 方法中 , 需要进行一些初始化的工作, 并需要构造Digester 对象, 用于解析 XML。
6.然后在调用后续组件的初始化操作 。。。加载Tomcat的配置文件,初始化容器组件 ,监听对应的端口号, 准备接受客户端请求