Tomcat 架构
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
一Http工作原理
HTTP
协议是浏览器与服务器之间的数据传送协议。作为应用层协议
HTTP
是基于
TCP/IP 协议来传递数据的HTML
文件、图片、查询结果等
HTTP
协议不涉及数据包Packet
传输主要规定了客户端和服务器之间的通信格式
从图上你可以看到这个过程是
1
用户通过浏览器进行了一个操作比如输入网址并回车或者是点击链接接着浏览
器获取了这个事件。
2
浏览器向服务端发出
TCP
连接请求。
3
服务程序接受浏览器的连接请求并经过
TCP
三次握手建立连接。
4
浏览器将请求数据打包成一个
HTTP
协议格式的数据包。
5
浏览器将该数据包推入网络数据包经过网络传输最终达到端服务程序。
6
服务端程序拿到这个数据包后同样以
HTTP
协议格式解包获取到客户端的意图。
7
得知客户端意图后进行处理比如提供静态文件或者调用服务端程序获得动态结果。
8
服务器将响应结果可能是
HTML
或者图片等按照
HTTP
协议格式打包。
9
服务器将响应数据包推入网络数据包经过网络传输最终达到到浏览器。
10
浏览器拿到数据包后以
HTTP
协议的格式解包然后解析数据假设这里的数据是
HTML
。
11
浏览器将
HTML
文件展示在页面上。
那我们想要探究的
Tomcat
作为一个
HTTP
服务器在这个过程中都做了些什么事情呢主
要是接受连接、解析请求数据、处理请求和发送响应这几个步骤。
二Tomcat整体架构
1.Http服务器请求处理
浏览器发给服务端的是一个
HTTP
格式的请求
HTTP
服务器收到这个请求后需要调用服务端程序来处理所谓的服务端程序就是你写的Java
类一般来说不同的请求需要由不同的Java
类来处理。
1
图
1
表示
HTTP
服务器直接调用具体业务类它们是紧耦合的。
2
图
2
HTTP
服务器不直接调用业务类而是把请求交给容器来处理容器通过Servlet接口调用业务类。因此
Servlet
接口和
Servlet
容器的出现达到了
HTTP
服务器与业务类解耦的目的。而Servlet
接口和
Servlet
容器这一整套规范叫作
Servlet
规范。 Tomcat按照
Servlet
规范的要求实现了
Servlet
容器同时它们也具有
HTTP
服务器的功 能。作为Java
程序员如果我们要实现新的业务功能只需要实现一个
Servlet
并把它注册到Tomcat
Servlet容器中剩下的事情就由
Tomcat
帮我们处理了。
2.Servlet容器工作流程
为了解耦
HTTP
服务器不直接调用
Servlet
而是把请求交给
Servlet
容器来处理那
Servlet
容器又是怎么工作的呢
当客户请求某个资源时
HTTP
服务器会用一个
ServletRequest
对象把客户的请求信息封
装起来然后调用
Servlet
容器的
service
方法
Servlet
容器拿到请求后根据请求的
URL 和Servlet
的映射关系找到相应的
Servlet
如果
Servlet
还没有被加载就用反射机制创建这个Servlet
并调用
Servlet
的
init
方法来完成初始化接着调用
Servlet
的
service
方法来处理请求把ServletResponse
对象返回给
HTTP
服务器
HTTP
服务器会把响应发送给客户端。
3. Tomcat整体架构
我们知道如果要设计一个系统首先是要了解需求我们已经了解了
Tomcat
要实现两个
核心功能
1
处理
Socket
连接负责网络字节流与
Request
和
Response
对象的转化。
2
加载和管理
Servlet
以及具体处理
Request
请求。
因此
Tomcat
设计了两个核心组件连接器
Connector
和容器
Container
来分别做这两件事情。连接器负责对外交流容器负责内部处理。
三连接器 - Coyote
1 .架构介绍
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
。
2.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
支持的应用层协议
应用层协
议
|
描述
|
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 HTTP
Server
的影响性能。
Tomcat
为了实现支持多种
I/O
模型和应用层协议一个容器可能对接多个连接器就好比
一个房间有多个门。但是单独的连接器或者容器都不能对外提供服务需要把它们组装起来才能工作组装后这个整体叫作Service
组件。这里请你注意
Service
本身没有做什么重要的事情只是在连接器和容器外面多包了一层把它们组装在一起。Tomcat
内可能有多个Service
这样的设计也是出于灵活性的考虑。通过在
Tomcat
中配置多个Service可以实现通过不同的端口号来访问同一台机器上部署的不同应用。
3. 连接器组件
连接器中的各个组件的作用如下
EndPoint
1
EndPoint
Coyote
通信端点即通信监听的接口是具体
Socket
接收和发送处理
器是对传输层的抽象因此
EndPoint
用来实现
TCP/IP
协议的。
2
Tomcat
并没有
EndPoint
接口而是提供了一个抽象类
AbstractEndpoint
里面定
义了两个内部类
Acceptor
和
SocketProcessor
。
Acceptor
用于监听
Socket
连接请求。
SocketProcessor
用于处理接收到的
Socket
请求它实现
Runnable
接口在
Run
方法里
调用协议处理组件
Processor
进行处理。为了提高处理能力
SocketProcessor
被提交到
线程池来执行。而这个线程池叫作执行器
Executor)
我在后面的专栏会详细介绍
Tomcat
如何扩展原生的
Java
线程池。
Processor
Processor
Coyote
协议处理接口 如果说
EndPoint
是用来实现
TCP/IP
协议的那么
Processor
用来实现
HTTP
协议
Processor
接收来自
EndPoint
的
Socket
读取字节流解
析成
Tomcat Request
和
Response
对象并通过
Adapter
将其提交到容器处理
Processor
是对应用层协议的抽象。
ProtocolHandler
ProtocolHandler
Coyote
协议接口 通过
Endpoint
和
Processor
实现针对具体协
议的处理能力。
Tomcat
按照协议和
I/O
提供了
6
个实现类
AjpNioProtocol ,
AjpAprProtocol
AjpNio2Protocol
Http11NioProtocol
Http11Nio2Protocol
Http11AprProtocol。我们在配置
tomcat/conf/server.xml
时 至少要指定具体的 ProtocolHandler , 当然也可以指定协议名称 如
HTTP/1.1
如果安装了
APR
那么将使用Http11AprProtocol
否则使用
Http11NioProtocol
。
Adapter
由于协议不同客户端发过来的请求信息也不尽相同
Tomcat
定义了自己的
Request
类
来
“
存放
”
这些请求信息。
ProtocolHandler
接口负责解析请求并生成
Tomcat Request
类。
但是这个
Request
对象不是标准的
ServletRequest
也就意味着不能用
Tomcat ,Request作为参数来调用容器。
Tomcat
设计者的解决方案是引入
CoyoteAdapter
这是适配器模式的经典运用连接器调用CoyoteAdapter
的
Sevice
方法传入的是
Tomcat,Request对象
CoyoteAdapter
负责将
Tomcat Request
转成
ServletRequest
再调用容器的Service
方法。
四 .容器 - Catalina
Tomcat
是一个由一系列可配置的组件构成的
Web
容器而
Catalina
是
Tomcat
的
servlet
容
器。
Catalina
是
Servlet
容器实现包含了之前讲到的所有的容器组件以及后续章节涉及到
的安全、会话、集群、管理等
Servlet
容器架构的各个方面。它通过松耦合的方式集成 Coyote以完成按照请求协议进行数据读写。同时它还包括我们的启动入口、
Shell
程序等。
1.Catalina 地位
Tomcat
的模块分层结构图 如下
Tomcat
本质上就是一款
Servlet
容器 因此
Catalina
才是
Tomcat
的核心 其他模块 都是为Catalina
提供支撑的。 比如 通过
Coyote
模块提供链接通信
Jasper
模块提供JSP引擎
Naming
提供
JNDI
服务
Juli
提供日志服务。
2 .Catalina 结构
Catalina
的主要组件结构如下
如上图所示
Catalina
负责管理
Server
而
Server
表示着整个服务器。
Server
下面有多个服务Service
每个服务都包含着多个连接器组件
Connector
Coyote
实现和一个容器组Container
。在
Tomcat
启动的时候 会初始化一个
Catalina
的实例。
Catalina
各个组件的职责
组件
|
职责
|
Catalina
|
负责解析
Tomcat
的配置文件
,
以此来创建服务器
Server
组件并根据命令来对其进行管理
|
Server
|
服务器表示整个
Catalina Servlet
容器以及其它组件负责组装并启动Servlet引擎
,Tomcat
连接器。
Server
通过实现
Lifecycle
接口提供了 一种优雅的启动和关闭整个系统的方式
|
Service
|
服务是
Server
内部的组件一个
Server
包含多个
Service
。它将若干个Connector组件绑定到一个
Container
Engine
上
|
Connector
|
连接器处理与客户端的通信它负责接收客户请求然后转给相关的容器处理最后向客户返回响应结果
|
Container
|
容器负责处理用户的
servlet
请求并返回对象给
web
用户的模块
|
3.Container 结构
Tomcat
设计了
4
种容器分别是
Engine
、
Host
、
Context
和
Wrapper
。这
4
种容器不是平
行关系而是父子关系.
Tomcat
通过一种分层的架构使得
Servlet
容器具有很好的灵
活性。
各个组件的含义
容器
|
描述
|
Engine
|
表示整个
Catalina
的
Servlet
引擎用来管理多个虚拟站点一个
Service最多只能有一个Engine
但是一个引擎可包含多个
Host
|
Host
|
代表一个虚拟主机或者说一个站点可以给
Tomcat
配置多个虚拟主机地址而一个虚拟主机下可包含多个Context
|
Context
|
表示一个
Web
应用程序 一个
Web
应用可包含多个
Wrapper
|
Wrappe
|
表示一个
Servlet
Wrapper
作为容器中的最底层不能包含子容器
|
我们也可以再通过
Tomcat
的
server.xml
配置文件来加深对
Tomcat
容器的理解。
Tomcat
采用了组件化的设计它的构成组件都是可配置的其中最外层的是
Server
其他组件
按照一定的格式要求配置在这个顶层容器中。
那么Tomcat是怎么管理这些容器的呢你会发现这些容器具有父子关系形成一个树形结构你可能马上就想到了设计模式中的组合模式。没错Tomcat就是用组合模式来管理这些容器的。具体实现方法是所有容器组件都实现了Container接口因此组合模式可以使得用户对单容器对象和组合容器对象的使用具有一致性。这里单容器对象指的是最底层的Wrapper组合容器对象指的是上面的Context、Host或者Engine。
Container 接口中提供了以下方法截图中知识一部分方法
在上面的接口看到了
getParent
、
SetParent
、
addChild
和
removeChild
等方法.Container接口扩展了
LifeCycle
接口
LifeCycle
接口用来统一管理各组件的生命周期.