当前位置: 首页 > news >正文

Tomcat 架构

一、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的整体架构

        1.Http服务器请求处理

        浏览器发给服务端的是一个HTTP格式的请求,HTTP服务器收到这个请求后,需要调用服务端程序来处理,所谓的服务端程序就是你写的Java类,一般来说不同的请求需要由不同的Java类来处理。

        图1,表示HTTP服务器直接调用具体业务类,它们是紧耦合的。

        图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要实现两个核心功能:

        处理Socket连接,负责网络字节流与Request和Response对象的转化。

        加载和管理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.I/O模型与协议

        在Coyote中,Tomcat支持的多种I/O模型和应用层协议,具体包含哪些I/O模型和应用层协议,请看下表:

        Tomcat支持的IO模型(自8.5/9.0版本起,Tomcat移除了对 BIO的支持):

        Tomcat支持的应用层协议:

        协议分层:

        在 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)。

        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方法,传入的是TomcatRequest对象,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 各个组件的职责:

        3.Container 结构

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

        各个组件的含义 :

        我们也可以再通过Tomcat的server.xml配置文件来加深对Tomcat容器的理解。Tomcat采用了组件化的设计,它的构成组件都是可配置的,其中最外层的是Server,其他组件按照一定的格式要求配置在这个顶层容器中。

        那么,Tomcat是怎么管理这些容器的呢?你会发现这些容器具有父子关系,形成一个树形结构,你可能马上就想到了设计模式中的组合模式。没错,Tomcat就是用组合模式来管理这些容器的。具体实现方法是,所有容器组件都实现了Container接口,因此组合模式可以使得用户对单容器对象和组合容器对象的使用具有一致性。这里单容器对象指的是最底层的Wrapper,组合容器对象指的是上面的Context、Host或者Engine。

        Container 接口中提供了以下方法(截图中知识一部分方法):

        在上面的接口看到了getParent、SetParent、addChild和removeChild等方法。

        Container接口扩展了LifeCycle接口,LifeCycle接口用来统一管理各组件的生命周期。

相关文章:

  • ComfyUI中的翻译节点(Deep Translator Text Node)怎么用
  • openGauss学习笔记-232 openGauss性能调优-系统调优-资源负载管理-资源管理准备-资源规划
  • 掘根宝典之C语言字符串输出函数(puts(),fputs())
  • 数据迁移DTS | 云上MySQL 数据库迁移至达梦数据库
  • JavaScript-关于事件、事件流(捕获、冒泡)、事件源、常用事件
  • 总结springboot启动jar,指定配置文件
  • PCB Layout完成后,检查注意事项
  • 单点故障解决方案之Smart Link与Monitor Link
  • <网络安全>《62 微课堂<第2课 流量限制是什么?>》
  • MATLAB知识点:利用智能缩进整理代码
  • 3.1日学习打卡----初学FastDFS(一)
  • 【01】openEuler 源码安装 PostgreSQL
  • LabVIEW最佳传输系统设计
  • elment-ui table表格排序后 清除排序箭头/恢复默认排序 的高亮样式
  • 【leetcode热题】被围绕的区域
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • js面向对象
  • JS数组方法汇总
  • js正则,这点儿就够用了
  • laravel 用artisan创建自己的模板
  • Next.js之基础概念(二)
  • node入门
  • Python3爬取英雄联盟英雄皮肤大图
  • Vim Clutch | 面向脚踏板编程……
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • vue--为什么data属性必须是一个函数
  • 大主子表关联的性能优化方法
  • 记一次和乔布斯合作最难忘的经历
  • 前端技术周刊 2019-02-11 Serverless
  • 前端知识点整理(待续)
  • 前嗅ForeSpider采集配置界面介绍
  • 设计模式走一遍---观察者模式
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 提醒我喝水chrome插件开发指南
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • Prometheus VS InfluxDB
  • 函数计算新功能-----支持C#函数
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (第二周)效能测试
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (转) 深度模型优化性能 调参
  • (转)http协议
  • (转)我也是一只IT小小鸟
  • (转载)OpenStack Hacker养成指南
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .net 7 上传文件踩坑
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .net 验证控件和javaScript的冲突问题