目录
- 02 HTTP 必知必会
- 03 Servlet容器
- 04 Tomcat系统架构-连接器
- 05 Tomcat系统架构-容器
- 06 Tomcat请求过程流转
- 07 Tomcat启动流程
- 08 NioEndpoint组件:Tomcat如何实现非阻塞I/O?
- 09 Tomcat如何实现异步I/O
- 10 AprEndpoint组件: Tomcat Apr 提高I/O性能
- 11 Tomcat的线程池技术
- 12 Tomcat实现WebSocket
- 13 Tomcat热加载 和 热部署
- 14 tomcat如何打破双亲委派政策
- 15 tomcat如何隔离多web应用
- 16 Tomcat如何实现Servlet规范
- 17 Tomcat如何实现异步Servlet
- 18. SpringBoot 支持Tomcat
- 19 SpringBoot如何管理Session
- 20 Tomcat 集群通讯组件原理
- 参考
02 HTTP 必知必会
因为http是无状态的 所以出现了,cookies 存储状态信息,但是存储在本地不安全,这么也就有了 session,存储在服务器端,配合cooikes来进行标识;
03 Servlet容器
Servlet其实是一个接口,定义了servlet规范。一个http请求 到服务器的工作流程如下:
1、将请求信息封装成ServletRequest
2、调用servlet的service方法
3、如果不存在,那么就调用init方法创建
4、调用service方法,然后返回reponse对象,返回给客户端
servlet容器,web容器,spring容器,springmvc容器的区别;
并且SpringMVC容器是Spring容器的子容器,所谓的父子关系意味着什么呢,就是你通过子容器去拿某个Bean时,子容器先在自己管理的Bean中去找这个Bean,如果找不到再到父容器中找。但是父容器不能到子容器中去找某个Bean。父容器 不能依赖子容器;
上图来源于网络
04 Tomcat系统架构-连接器
tomcat设计了两个核心组件:连接器Connector, 容器Container;连接负责对外交流,容器负责内部处理;
1、监听网络端口
2、接收网络请求连接
3、将请求解析转换为 Tomcat Request 对象
4、将Tomcat Request 转换为 Servlet Request
**5、调用Servlet 获得 Servlet Response **
6、将获得的结果转换,响应返回给前端
根据上述功能,Tomcat 就把它抽象成了三个核心类,EndPoint 、Process、Adapter 来分别处理
- 网络通信
- 应用层协议解析
- Tomcat Request 到 Servlet的转换
组件之间通过接口进行交互,封装变化,将系统中经常变化的部分,和稳定的部分进行隔离;有助于增加复用性,并降低系统的耦合度;
其交互处理的逻辑如下:
![](https://www.icode9.com/i/ll/?i=img_convert/5e2024ddb47977c566fb9ecf32972c16.png#clientId=u604cc54a-cf5a-4&from=paste&height=266&id=u10206821&margin=[object Object]&name=image.png&originHeight=532&originWidth=1450&originalType=binary&ratio=1&size=208315&status=done&style=none&taskId=uab577043-6cae-4a92-9ed6-fa2cfa67b4a)
4.1 ProtocolHandler 组件
这个组件内部包含两个组件,EndPoint 和 Processor;
**EndPoint: **负责通信的端点,是具体的Socket接收和发送的处理器,该组件是实现Tcp/Ip 协议的(内部有个线程池处理请求)
**Processor:**用来实现 HTTP 协议,Processor 接收来自 EndPoint 的 Socket,读取字节流解析成 Tomcat Request 和Response 对象,并通过 Adapter 将其提交到容器处理,Processor 是对应用层协议的抽象。
EndPoint 负责底层 Socket通信,Proccesor 负责应用层协议解析。连接器通过适配器 Adapter 转换调用容器。
05 Tomcat系统架构-容器
容器的层次结构,Tomcat设计了4种容器,分别是Engin 、Host、Context 、Wapper
他们是一个包含关系。Tomcat 通过一种分层的架构,使得 Servlet 容器具有很好的灵活性。
- Context 表示一个 Web 应用程序;
- Wrapper 表示一个 Servlet,一个 Web 应用程序中可能会有多个 Servlet;
- Host 代表的是一个虚拟主机,或者说一个站点,可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可以部署多个 Web 应用程序;
- Engine 表示引擎,用来管理多个虚拟站点,一个 Service 最多只能有一个 Engine。
上图展示了,根据Url是如何找到对应的wapper进行处理;
连接器中Adapter 会调用容器的 Service 方法来执行 Servlet,最先拿到请求的是 Engine 容器,Engine 容器对请求做一些处理后,会把请求传给自己子容器 Host 继续处理,依次类推,最后这个请求会传给 Wrapper 容器,Wrapper 会调用最终的 Servlet 来处理。那么这个调用过程具体是怎么实现的呢?
答案是使用 Pipeline-Valve 管道。
- Pipeline-Valve 是责任链模式,责任链模式是指在一个请求处理的过程中有很多处理者依次对请求进行处理,每个处理者负责做自己相应的处理,处理完之后将再调用下一个处理者继续处理。
在连接器里 会有一个触发调用 Engine的一个 value,然后以责任链的模式不断传递,Wrapper 容器的最后一个 Valve 会创建一个 Filter 链,并调用 doFilter() 方法,最终会调到 Servlet 的 service 方法
06 Tomcat请求过程流转
组件是如何创建,初始化,销毁的呢,管理他们的生命周期是一个很关键的问题?如何实现一键启动?
答:tomcat的核心组件都抽象出公共的部分 lifecycle接口其中定义了:init()、start()、stop() 和 destroy()这么几个核心方法;在父组件中创建的时候需要调用子组件的init方法。所以只要调用顶层的 Service的init方法,整个tomcat就启动了。
这是lifecyle的模版方法
@Override
public final synchronized void init() throws LifecycleException {
// 1、判断状态
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
// 2 触发 INITIALIZING 事件的监听器
setStateInternal(LifecycleState.INITIALIZING, null, false);
// 3 调用子类初始化方法
initInternal();
// 触发 INITIALIZED 事件的监听器
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
}
}
Tomcat 自定义了一些监听器,这些监听器是父组件在创建子组件的过程中注册到子组件的。比如 MemoryLeakTrackingListener 监听器,用来检测 Context 容器中的内存泄漏,这个监听器是 Host 容器在创建 Context 容器时注册到 Context 中的。我们还可以在 server.xml 中定义自己的监听器,Tomcat 在启动时会解析 server.xml,创建监听器并注册到容器组件。
整体类图:
07 Tomcat启动流程
通常我通过执行tomcat bin下的 startup.sh 脚本启动tomcat,那么tomcat到底是如何启动的呢? 具体流程如下:
7.1 Catalina 组件
它是个启动类,通过解析server.xml ,创建相应的组件,并调用server的start方法,向下传递启动。Catalina是一个管理则者的身份,它还需要处理各种异常场景,当发生 ctrl+ c 强制关闭时,是如何释放资源的。Catalina在JVM中注册了一个关闭的钩子。
public void start() {
if (getServer() == null) {
load();
}
if (getServer() == null) {
log.fatal("Cannot start server. Server instance is not configured.");
return;
}
long t1 = System.nanoTime();
// Start the new server
try {
getServer().start();
} catch (LifecycleException e) {
return;
}
// Register shutdown hook
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
// 注册一个jvm的回调函数;内部其实是进行资源的释放和清理
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
// 监听停止请求
if (await) {
await();
stop();
}
}
7.2 Server 组件
Server的具体实现类是StandServer.这个组件会管理 service的生命周期。在server内部维护着多个service组件。还有一个重要的任务就是,启动Socket来监听停止端口。
7.2 Service 组件
Service组件的具体实现类是StandardService,
/**
*
* 这是service 实例
*
*/
private Server server = null;
/**
*
* 连接器
*/
protected Connector connectors[] = new Connector[0];
private final Object connectorsLock = new Object();
/**
* engine容器
*
*/
private Engine engine = null;
@Override
protected void startInternal() throws LifecycleException {
// 1、触发启动监听器
setState(LifecycleState.STARTING);
// 2、启动引擎
if (engine != null) {
synchronized (engine) {
engine.start();
}
}
// 3、mapper监听器 热加载部署
mapperListener.start();
// 4、连接器的启动 内部会启动子组建 如:endoint组件
synchronized (connectorsLock) {
for (Connector connector: connectors) {
connector.start();
}
}
}
}
service作为管理者,最重要的是维护其他组件的生命周期;启动组件时要维护依赖关系。
7.3 Engine组件
engine组件的本质是一个容器,它继承了ContainerBase基类,并实现了Engine接口
08 NioEndpoint组件:Tomcat如何实现非阻塞I/O?
uninx下有5种IO模型:同步阻塞IO, 同步非阻塞IO, IO多路复用,信号驱动IO, 异步IO。见:
原文地址:https://blog.csdn.net/weixin_43732955/article/details/120919147
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。