【博学谷学习记录】超强总结,用心分享 | 架构师 Tomcat源码学习总结
文章目录
- Tomcat
- Tomcat功能需求分析
- Tomcat两个非常重要的功能(身份)
- Tomcat的架构(设计实现)
- 连接器的设计
- 连接器架构分析
- 核心功能
- ProtocolHandler 组件
- 1.EndPoint组件
- EndPoint类结构图
- 2.Processor组件
- Processor类结构图
- 3.Adapter组件
- 4.ProtocolHandler组件
- ProtocolHandler类图
- Connector处理流程
- 容器
- 容器的本质
- 容器工作流程
- 容器层次结构
- 组件类图
- 套娃式架构设计的好处
Tomcat
Tomcat功能需求分析
浏览器发给服务端的是一个 HTTP 格式的请求,HTTP 服务器收到这个请求后,需要调用服务端程序来处理,所谓的服务端程序就是你写的 Java 类,一般来说不同的请求需要由不同的 Java 类来处理。那么问题来了,HTTP 服务器怎么知道要调用哪个 Java 类的哪个方法呢?
- HTTP 服务器直接调用具体业务类,它们是紧耦合的。
解决:HTTP 服务器不直接调用业务类,而是把请求交给容器来处理,容器通过 Servlet 接口调用业务
类。因此 Servlet 接口和 Servlet 容器的出现,达到了 HTTP 服务器与业务类解耦的目的。
Tomcat两个非常重要的功能(身份)
- Http服务器功能:Socket通信(TCP/IP)、解析Http报文
- Servlet容器功能:有很多Servlet(自带系统级Servlet+自定义Servlet),Servlet处理具体的业务逻辑
Tomcat的架构(设计实现)
Tomcat的需求是要实现 2 个核心功能:
- 处理 Socket 连接,负责网络字节流与 Request 和 Response 对象的转化。
- 加载和管理 Servlet,以及具体处理 Request 请求。
基于Tomcat需求,所以 Tomcat 设计了两个核心组件连接器(Connector)和容器(Container)来分别做这两件事情。
连接器负责对外交流,容器负责内部处理。
Tomcat中一个容器可能对接多个连接器,每一个连接器都对应某种协议某种IO模型,Tomcat将多个连接器和单个容器组成一个service组件,一个tomcat中可能存在多个Service组件
- Connector:将不同协议不同IO模型的请求转换为标准的标准的 ServletRequest 对象交给容器处理。
- Container:Container本质上是一个Servlet容器,负责servelt的加载和管理,处理请求ServletRequest,并返回标准的 ServletResponse 对象给连接器。
连接器的设计
铺垫:Tomcat 是支持多种 I/O 模型和应用层协议的
Tomcat 支持的 I/O 模型有:
- NIO:非阻塞 I/O,采用 Java NIO 类库实现
- NIO.2:异步 I/O,采用 JDK 7 最新的 NIO.2 类库实现
- APR:采用 Apache 可移植运行库实现,是 C/C++ 编写的本地库
Tomcat 支持的应用层协议有:
- TP/1.1:这是大部分 Web 应用采用的访问协议
- AJP:用于和 Web 服务器集成(如 Apache)
- HTTP/2:HTTP 2.0 大幅度的提升了 Web 性能
连接器架构分析
Tomcat 为了实现支持多种 I/O 模型和应用层协议,一个容器可能对接多个连接器,就好比一个房间有多个门。但是单独的连接器或者容器都不能对外提供服务,需要把它们组装起来才能工作,组装后这个整体叫作 Service 组件。这里请注意,Service 本身没有做什么重要的事情,只是在连接器和容器外面多包了一层,把它们组装在一起。Tomcat 内可能有多个 Service,这样的设计也是出于灵活性的考虑。通过在 Tomcat 中配置多个 Service,可以实现通过不同的端口号来访问同一台机器上部署的不同应用。
最顶层是 Server,这里的 Server 指的就是一个 Tomcat 实例。一个 Server 中有一个或者多个 Service,一个 Service 中有多个连接器和一个容器。连接器与容器之间通过标准的ServletRequest 和 ServletResponse 通信。
核心功能
连接器对 Servlet 容器屏蔽了协议及 I/O 模型等的区别,无论是 HTTP 还是 AJP,在容器中获取到的都是一个标准的 ServletRequest 对象。我们可以把连接器的功能需求进一步细化,比如:
- 监听网络端口。
- 接受网络连接请求。读取网络请求字节流。
- 根据具体应用层协议(HTTP/AJP)解析字节流,生成统一的 Tomcat Request 对象。
- 将 Tomcat Request 对象转成标准的 ServletRequest。
- 调用 Servlet 容器,得到 ServletResponse。
- 将 ServletResponse 转成 Tomcat Response 对象。
- 将 Tomcat Response 转成网络字节流。
- 将响应字节流写回给浏览器。
连接器需要完成 3 个高内聚的功能:
- 网络通信
- 应用层协议解析
- Tomcat Request/Response 与 ServletRequest/ServletResponse 的转化
因此 Tomcat 的设计者设计了 3 个组件来实现这 3 个功能,分别是 Endpoint、Processor 和 Adapter。
由于 I/O 模型和应用层协议可以自由组合,比如 NIO + HTTP 或者 NIO.2 + AJP。Tomcat 的设计者将网络通信和应用层协议解析放在一起考虑,设计了一个叫 ProtocolHandler 的接口来封装这两种变化点
通过图清晰地看到它们的继承和层次关系,这样设计的目的是尽量将稳定的部分放到抽象基类,同时每一种 I/O 模型和协议的组合都有相应的具体实现类,我们在使用时可以自由选择。
ProtocolHandler 组件
1.EndPoint组件
Endpoint 翻译过来是"通信端点",主要负责网络通信,这其中就包括,监听客户端连接创建与客户端连接的Socket,并负责连接Socket 接收和发送处理器。因此Endpoint是对传输层的抽象,是用来实现 TCP/IP 协议的
EndPoint类结构图
EndPoint用基类用抽象类AbstractEndpoint来表示,对于不同的Linux IO模型通过使用不同子类来实现。
Endpoint 是一个接口,对应的抽象实现类是 AbstractEndpoint,而 AbstractEndpoint 的具体子类,比如在 NioEndpoint 和 Nio2Endpoint 中,有两个重要的子组件:Acceptor 和 SocketProcessor
其中 Acceptor 用于监听 Socket 连接请求。SocketProcessor 用于处理接收到的 Socket 请求,它实现Runnable 接口,在 run 方法里调用协议处理组件 Processor 进行处理。为了提高处理能力,SocketProcessor 被提交到线程池来执行。而这个线程池叫作执行器(Executor)
Acceptor接收连接包装Socket 给Poller
Poller:做IO事件检测,有IO事件绑定到一个SocketProcessorBase提交到线程中执行
线程池中:调用Processor完成协议解析,解析完后将请求交给Adapter
2.Processor组件
Processor:翻译过来是"处理器",主要负责根据具体应用层协议(HTTP/AJP)读取字节流解析成Tomcat Request 和 Response,因此Processor是对应用层的抽象,是用来实现 HTTP/AJP 协议的。
Processor类结构图
Processor 是一个接口,定义了请求的处理等方法。它的抽象实现类 AbstractProcessor 对一些协议共有的属性进行封装,没有对方法进行实现。具体的实现有 AjpProcessor、Http11Processor 等,这些具体实现类实现了特定协议的解析方法和请求处理方式
3.Adapter组件
由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat 定义了自己的 Request 类来“存放”这些请求信息。ProtocolHandler 接口负责解析请求并生成 Tomcat Request/Response类。但是这个Request/Response 对象不是标准的 ServletRequest/ServletResponse,也就意味着,不能用TomcatRequest/Response 作为参数来调用容器。
Tomcat 设计者的解决方案是引入 CoyoteAdapter,这是适配器模式的经典运用,负责将Tomcat
Request/Response 与 ServletRequest/ServletResponse 的相互转化,实现连接器(Connector)和容器(Container)的解耦。
4.ProtocolHandler组件
ProtocolHandler组件EndPoint组件,Processor组件合并在一起表示协议处理器。用来处理tomcat支持多种IO模型和多种协议的组件。
ProtocolHandler类图
Connector处理流程
Endpoint内部Acceptor组件用于监听Socket 连接请求,当发送客户端连接到服务端Acceptor组件负责与客户端建立连接创建Socket,每当连接客户端发起请求,Endpoint会创建一个
SocketProcessor对象SocketProcessor 用于处理接收到的 Socket 请求,它实现 Runnable 接口,在 run 方法里调用协议处理组件 Processor 进行处理。为了提高处理能力,SocketProcessor 被提交到线程池来执行。而这个线程池叫作执行器(Executor)
Processor 接收来自 Endpoint 的 Socket,读取字节流解析成 Tomcat Request 和 Response 对象,接着会调用 Adapter 的 Service 方法。并通过 Adapter 将其提交到容器处理
连接器调用 CoyoteAdapter 的 sevice 方法,传入的是 Tomcat Request 对象,CoyoteAdapter 负责将 Tomcat Request 转成 ServletRequest,再调用容器的 service 方法。
容器
容器的本质
Tomcat 有两个核心组件:连接器和容器
Container本质上是一个Servlet容器,负责servelt的加载和管理,处理请求ServletRequest,并返回标准的ServletResponse 对象给连接器。
容器工作流程
当客户请求某个资源时,HTTP 服务器会用一个 ServletRequest 对象把客户的请求信息封装起来,然后调用Servlet 容器的 service 方法,Servlet 容器拿到请求后,根据请求的 URL 和 Servlet 的映射关系,找到相应的Servlet,如果 Servlet 还没有被加载,就用反射机制创建这个 Servlet,并调用 Servlet 的init 方法来完成初始化,接着调用 Servlet 的 service 方法来处理请求,把 ServletResponse 对象返回给HTTP 服务器,HTTP 服务器会把响应发送给客户端
容器层次结构
Tomcat 设计了 4 种容器组件,分别是 Engine、Host、Context 和 Wrapper。这 4 种容器不是平行关系,而是父子关系。
- Wrapper:表示一个 Servlet
- Context:表示一个 Web 应用程序,一个 Web 应用程序中可能会有多个 Servlet
- Host:表示的是一个虚拟主机,或者说一个站点,可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可以部署多个 Web 应用程序
- Engine:表示引擎,用来管理多个虚拟站点,一个 Service 最多只能有一个 Engine。
可以再通过 Tomcat 的server.xml配置文件来加深对 Tomcat 容器的理解。Tomcat 采用了组件化的设计,它的构成组件都是可配置的,其中最外层的是 Server,其他组件按照一定的格式要求配置在这个顶层容器中。
组件类图
Container容器中定义了Container 接口用来描述Container容器中所有的组件,不同的子组件分别定义了不同子接口做描述。容器组件之间具有父子关系。
从接口看到了 getParent、setParent、addChild 和 removeChild 等方法。可能还注意到 Container 接口扩展了 Lifecycle 接口,Lifecycle 接口用来统一管理各组件的生命周期
套娃式架构设计的好处
- 一层套一层的方式,其实组件关系还是很清晰的,也便于后期组件生命周期管理
- tomcat这种架构设计正好和xml配置文件中标签的包含方式对应上,那么后续在解读xml以及封装对象的过程中就容易对应
- 便于子容器继承父容器的一些配置
相关文章:
【博学谷学习记录】超强总结,用心分享 | 架构师 Tomcat源码学习总结
文章目录TomcatTomcat功能需求分析Tomcat两个非常重要的功能(身份)Tomcat的架构(设计实现)连接器的设计连接器架构分析核心功能ProtocolHandler 组件1.EndPoint组件EndPoint类结构图2.Processor组件Processor类结构图3.Adapter组件…...
泛型<E>
泛型 案例引出泛型 按要求写出代码: 在ArrayList中添加3个Dog对象,Dog对象有name和age两个属性,且输出name和age public class test1 {public static void main(String[] args) {ArrayList list new ArrayList();list.add(new Dog(10,&quo…...
你对MANIFEST.MF这个文件知道多少?
前言我们在读源码过程中,经常看到每个jar包的METE-INF目录下有个MANIFEST.MF文件,这个文件到底是做什么的呢?在计算机领域中,"manifest" 通常指的是一份清单或概要文件,用于描述一组文件或资源的内容和属性。…...
史上最经典垃圾回收器(CMS,G1)详解、适用场景及特点、使用命令
文章目录垃圾收集器介绍总结各个垃圾收集器之间的关系垃圾收集器使用命令及默认值详解各个垃圾收集器SerialParNewParallel ScavengeSerial OldParallel OldCMS(Concurrent Mark Sweep)G1(Garbage First)适用场景及推荐垃圾收集器介绍总结 垃圾收集器可以帮助我们进行具体的垃…...
Hive查询中的优化
目录前言优化策略推荐使用group by代替distinct去重前言 优化策略 推荐使用group by代替distinct去重 参考: hive中groupby和distinct区别以及性能比较 - cnblogs数据倾斜之count(distinct) - cnblogs 重要结论: 两者都会在map阶段count,…...
【开发规范】go项目开发中的[流程,git,代码,目录,微服务仓库管理,静态检查]
文章目录前言一、有哪些规范我们应该遵循二、项目开发流程三、git的代码分支管理1. 分支管理2. commit规范三、go的代码规范四、go项目目录规范五、微服务该采用multi-repo还是mono-repo?1. 引言2. Repos 是什么?3. 什么是 Mono-repo?4. Mono-repo 的劣势5. 什么是…...
数组初始化方式与decimal.InvalidOperation
数组初始化方式与decimal.InvalidOperation调用函数主函数: 数组声明不同带来的报错与否1. 报错decimal.InvalidOperation的数组初始化版本2. 可行的初始化版本输出结果1. 报错时的内容2. 正常的输出计算结果原因(是否是数组与列表不同引起(?…...
【Opencv-python】之入门安装
目录 一、安装Python 1. 登录官网https://www.python.org/downloads/ 2. 任选一个版本,下载Python 3. 安装Python 记得勾选下图的Add Python 3.6 PATH, 添加python到环境变量的路径,然后选择Install now编辑 4. 验证是否安装成功 5.退出 二、安装…...
MySQL进阶(二)
目录 1、视图 1、检查选项 2、视图的更新 3、视图作用 2、存储过程 1、语法 2、变量 1、系统变量 2、用户定义变量 3、局部变量 3、if 4、参数 5、case 6、循环 1、while 2、repeat 3、loop 7、游标、条件处理程序 8、存储函数 3、触发器 4、锁 1、全局锁 2、表级锁 …...
热爱所有热爱
想成为这样的一个人,在工作中是一名充满极客精神的Programmer,处理遇到的问题能够游刃有余,能够做出优雅的设计,写出一手优秀的代码,还有着充分的学习能力和业务能力,做一名职场中的佼佼者。 在工作之余还能…...
Redis学习之数据删除与淘汰策略(七)
这里写目录标题一、Redis数据特征二、过期数据三、过期数据删除策略3.1 数据删除策略的目标3.2 定时删除3.3 惰性删除3.4 定期删除3.5 删除策略对比3.6 实际应用四、数据淘汰策略4.1 淘汰策略概述4.2 策略配置一、Redis数据特征 Redis是一种内存级数据库,所有的数据…...
HashMap 面试专题
1、HashMap 的底层结构 ①JDK1.8 以前 JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列。HashMap 通过 key 的hashCode 函数处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的长度…...
域组策略自动更新实验报告
域组策略自动更新实验报告 域组策略自动更新实验报告 作者: 高兴源 1要求、我公司为了完善员工的安全性和系统正常漏洞的维护,所以采用域组策略自动更新的方法来提高账户安全性,减少了用户的错误。 1.实验环境如下1台2008r2一台创建域,一台wi…...
Java自定义生成二维码(兼容你所有的需求)
1、概述作为Java开发人员,说到生成二维码就会想到zxing开源二维码图像处理库,不可否认的是zxing确实很强大,但是实际需求中会遇到各种各样的需求是zxing满足不了的,于是就有了想法自己扩展zxing满足历史遇到的各种需求,…...
Spring事务的隔离级别
事务隔离级别解决的是多个事务同时调⽤⼀个数据库的问题 事务传播机制解决的是⼀个事务在多个节点(⽅法)中传递的问题 事务的特性: 隔离性:多个事务在并发执行的时候,多个事务执行的一个行为模式,当一个事务执行的时候,另一个事务执行的一个行…...
JVM系统优化实践(4):以支付系统为例
您好,我是湘王,这是我的CSDN博客,欢迎您来,欢迎您再来~前面说过,JVM会将堆内存划分为年轻代、老年代两个区域。年轻代会将创建和使用完之后马上就要回收的对象放在里面,而老年代则将创建之后需要…...
16- TensorFlow实现线性回归和逻辑回归 (TensorFlow系列) (深度学习)
知识要点 线性回归要点: 生成线性数据: x np.linspace(0, 10, 20) np.random.rand(20)画点图: plt.scatter(x, y)TensorFlow定义变量: w tf.Variable(np.random.randn() * 0.02)tensor 转换为 numpy数组: b.numpy()定义优化器: optimizer tf.optimizers.SGD()定义损失: …...
无自动化测试系统设计方法论
灵活 敏捷 迭代。 自动化测试 辩思 测试必不可少 想想看没有充分测试的代码, 哪一次是一次过的? 哪一次不需要经历下测试的鞭挞? 不要以为软件代码容易改, 就对于质量不切实际的自信—那是自大! 不适用自动化测试的case 遗留系统。太多的依赖方, 不想用过多的mock > …...
架构初探-学习笔记
1 什么是架构 有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。 1.1 单机架构 所有功能都实现在一个进程里,并部署在一台机器上。 1.2 单体架构 分布式部署单机架构 1.3 垂直应用架构 按应用垂直切分的单体架构 1.4 SOA架构 将…...
在成都想转行IT,选择什么专业比较好?
很多创新型的互联网服务公司的核心其实都是软件,创新的基础、运行的支撑都是软件。例如,软件应用到了出租车行业,就形成了巅覆行业的滴滴;软件应用到了金融领域,就形成互联网金融;软件运用到餐饮行业,就形成美团;软件运…...
【Spark分布式内存计算框架——Spark Streaming】4.入门案例(下)Streaming 工作原理
2.3 Streaming 工作原理 SparkStreaming处理流式数据时,按照时间间隔划分数据为微批次(Micro-Batch),每批次数据当做RDD,再进行处理分析。 以上述词频统计WordCount程序为例,讲解Streaming工作原理。 创…...
2、算法先导---思维能力与工具
题目 碎纸片的拼接复原(2013B) 内容 破碎文件的拼接在司法物证复原、历史文献修复以及军事情报获取等领域都有着重要的应用。传统上,拼接复原工作需由人工完成,准确率较高,但效率很低。特别是当碎片数量巨大,人工拼接很难在短时…...
WordPress 函数:add_theme_support() 开启主题自定义功能(全面)
add_theme_support() 用于在我们的当前使用的主题添加一些特殊的功能,函数一般写在主题的functions.php文件中,当然也可以再插件中使用钩子来调用该函数,如果是挂在钩子上,那他必须挂在after_setup_theme钩子上,因为 i…...
Winform控件开发(16)——Timer(史上最全)
前言: Timer控件的作用是按用户定义的时间间隔引发事件的计时器,说的直白点就是,他就像一个定时炸弹一样到了一定时间就爆炸一次,区别在于定时炸弹炸完了就不会再次爆炸了,但是Timer这个计时器到了下一个固定时间还会触发一次,上面那张图片就是一个典型的计时器,该定时器…...
游戏高度可配置化:通用数据引擎(data-e)及其在模块化游戏开发中的应用构想图解
游戏高度可配置化:通数据引擎在模块化游戏开发中的应用构想图解 ygluu 码客 卢益贵 目录 一、前言 二、模块化与插件 1、常规模块化 2、插件式模块化(插件开发) 三、通用数据引擎理论与构成 1、名字系统(数据类型…...
CountDownLatch与CyclicBarrier原理剖析
1.CountDownLatch 1.1 什么是CountDownLatch CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。 CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之…...
NLP中的对话机器人——预训练基准模型
引言 本文是七月在线《NLP中的对话机器人》的视频笔记,主要介绍FAQ问答型聊天机器人的实现。 场景二 上篇文章中我们解决了给定一个问题和一些回答,从中找到最佳回答的任务。 在场景二中,我们来实现: 给定新问题,从…...
C语言学习及复习笔记-【14】C文件读写
14 C文件读写 14.1打开文件 您可以使用 fopen( ) 函数来创建一个新的文件或者打开一个已有的文件,这个调用会初始化类型 FILE 的一个对象,类型 FILE包含了所有用来控制流的必要的信息。下面是这个函数调用的原型: FILE *fopen( const char…...
模拟退火算法优化灰色
clc; clear; close all; warning off; %% tic T01000; % 初始温度 Tend1e-3; % 终止温度 L200; % 各温度下的迭代次数(链长) q0.9; %降温速率 X[16.4700 96.1000 16.4700 94.4400 20.0900 92.5400 22.3900 93.3700 25.…...
Pandas怎么添加数据列删除列
Pandas怎么添加数据列 1、直接赋值 # 1、直接赋值df.loc[:, "最高气温"] df["最高气温"].str.replace("℃", "").astype("int32")df.loc[:, "最低气温"] df["最低气温"].str.replace("℃"…...
湘潭自适应网站建设 磐石网络/哪些平台可以发布推广信息
2.5.1. EnableConfigurationProperties 引用自定义 *.properties 配置文件 Application.java 涮锅配置NetkillerProperties.java是 ComponentScan 扫描范围,可以不用声明下面注解。 EnableConfigurationProperties(NetkillerProperties.class)import org.springfram…...
家装设计师怎么学/文章优化关键词排名
Matlab强大的函数库涉及各个领域 matlab各个领域的函数库:https://ww2.mathworks.cn/matlabcentral/fileexchange/ 发现向量arrayA中最小的Num个数 function [ minFlags ] findMinFlag( arrayA,num ) %FINDMINFLAG Summary of this function goes here % Deta…...
如何做独立手机网站/seo综合查询怎么用的
恭喜你! 你已经找到了大多数人都在使用的屏幕截图尺子的辅助工具.作为一个iOS开发者来说,我总觉得简单的应用程序来检查图片或截图中的对象/元素位置存在不足。现在通过本App很容易找到任意用户界面元素的位置和大小,特别是X/Y位置和宽度/高度/大小。这个应用程序是…...
网站建设与规划/软文写作的十大技巧
文章目录参考资料1. 线性回归1.1 概述应用举例1.2 分析1.3 对数线性回归1.4 过拟合、欠拟合如何解决L2正则化(岭回归)L1正则化(Lasso回归)ElasticNet回归1.5 线性回归要求因变量服从正态分布?2. 对数几率回归(logistic 回归)2.1 概述2.2 优点2.3 求解2.4…...
广告设计主要做什么/网络营销的seo是做什么的
问题 题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。 分析:这是一道很新颖的关于位运算的面试题。 首先我们考虑这个问题的一个…...
网站多语言包/网站运营主要做什么
拦截器(Interceptor) 拦截器可以监听程序的一个或所有方法。拦截器对方法调用流提供了细粒度控制。可以在无状态会话bean、有状态会话bean 和消息驱动bean 上使用它们。拦截器可以是同一bean 类中的方法或是一个外部类。下面介绍如何在Session Bean 类中使用外部拦截器类。Hell…...