tomcat基础架构剖析

 2023-09-15 阅读 25 评论 0

摘要:前言 关于tomcat,可以从很多个维度去分析,作为一款优秀的JavaEE容器,从架构设计,线程模型,设计模式等诸多方面可以成为我们日产工作的借鉴,打算通过几个小节的深入研究探讨一下tomcat中的核心内容 tomcat中间件?本篇从tomcat的总体

前言

关于tomcat,可以从很多个维度去分析,作为一款优秀的JavaEE容器,从架构设计,线程模型,设计模式等诸多方面可以成为我们日产工作的借鉴,打算通过几个小节的深入研究探讨一下tomcat中的核心内容

tomcat中间件?本篇从tomcat的总体架构出发,了解一下其优秀的架构设计

一次请求的完整过程

在这里插入图片描述

不管是使用springmvc,springboot还是servlet,一个请求从客户端发起到最终收到响应,大致经历的过程如下:

  • 容器接收到请求
  • 解析请求参数,并包装为容器的请求,根据请求路径匹配映射的servlet容器
  • servlet容器根据请求参数处理请求并返回结果

当然,这只是一个非常粗的步骤,在springmvc框架中,将这么几步拆分开去,又可以细化到更细腻度的步骤,但springmvc或者springboot,底层也是基于tomcat原生的servlet的思想,因此有必要先了解一下tomcat是如何处理一个完整的请求的

在这里插入图片描述
理解上面的这幅图首先我们可以知道,tomcat为了解耦,一个请求到达HTTP服务器,并不直接调用Servlet,而是把请求交给Servlet容器来处理,因此可以说,了解了servlet的工作原理,就基本上掌握了tomcat的工作原理了

servlet服务器请求处理流程

当客户请求某个资源时,HTTP服务器会用一个ServletRequest对象把客户的请求信息封 装,然后调用Servlet容器的service方法,Servlet容器拿到请求后,根据请求的URL 和Servlet的映射关系,找到相应的Servlet,如果Servlet还没有被加载,就用反射机制创 建这个Servlet,并调用Servlet的init方法来完成初始化,接着调用Servlet的service方法 来处理请求,把ServletResponse对象返回给HTTP服务器,HTTP服务器会把响应发送给 客户端

以上就是servlet容器的整个工作过程,但是到达servlet容器并处理请求,整个过程是由许多个小的步骤,各个组件的配合共同完成的,让我们分别来做了解

Tomcat整体架构

我们知道如果要设计一个系统,首先是要了解需求,我们已经了解了Tomcat要实现两个 核心功能

1) 处理Socket连接,负责网络字节流与Request和Response对象的转化
2) 加载和管理Servlet,以及具体处理Request请求

因此Tomcat设计了两个核心组件连接器(Connector)和容器(Container)来分别做这 两件事情。连接器负责对外交流,容器负责内部处理。

从大的方向来看,连接器和容器可以将tomcat从逻辑结构上进行一次划分

在这里插入图片描述

连接器 - Coyote

Coyote 是Tomcat的连接器框架的名称 , 是Tomcat服务器提供的供客户端访问的外部接 口。客户端通过Coyote与服务器建立连接、发送请求并接受响应,对应于tomcat源码中的Connector类

Coyote 封装了底层的网络通信(Socket 请求及响应处理),为Catalina 容器提供了统一 的接口,使Catalina 容器与具体的请求协议及IO操作方式完全解耦。Coyote 将Socket 输 入转换封装为 Request 对象,交由Catalina 容器进行处理,处理请求完成后, Catalina 通 过Coyote 提供的Response 对象将结果写入输出流,可以说,Coyote提供了一个类似中间人的角色,承接着socket的http请求到httpServletRequest请求的转化传递,在tomcat源码中CoyoteAdapter的实现,后续章节中会加以说明

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

在这里插入图片描述

在研究tomcat的过程中,个人认为最好是从server.xml文件看起,这个文件的层次结构可以说很大一部分程度上反映了tomcat逻辑上的各个组件的结构,主要是这个文件的层次感太强了,组件之间的嵌套关系一眼便知,下面贴出了tomcat8X版本的srver.xml的配置文件,去掉了注释

<?xml version="1.0" encoding="UTF-8"?><Server port="8005" shutdown="SHUTDOWN"><Listener className="org.apache.catalina.startup.VersionLoggerListener" /><Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /><!-- Prevent memory leaks due to use of particular java/javax APIs--><Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /><Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /><Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /><GlobalNamingResources><Resource name="UserDatabase" auth="Container"type="org.apache.catalina.UserDatabase"description="User database that can be updated and saved"factory="org.apache.catalina.users.MemoryUserDatabaseFactory"pathname="conf/tomcat-users.xml" /></GlobalNamingResources><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /><Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /><Engine name="Catalina" defaultHost="localhost"><Realm className="org.apache.catalina.realm.LockOutRealm"><Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/></Realm><Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true"><Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" /></Host></Engine></Service></Server>

想要搞清楚tomcat的各种流程图或者架构图,对该文件的各个关键标签的含义,有必要进行理论上上的掌握

连接器组件

在上面的一张图中,我们简单了解了tomcat主要可以分为连接器(connector)和容器(Container),那么它们各自的组件下,又由那些小的组件构成呢?

在这里插入图片描述
从server.xml也可以看出来,一个容器可能对接多个连接器。但是单独的连接器或者容器都不能对外提供服务,需要把它们组装起来才能工作,组装后这个整体叫作Service组件。这里注意,Service本身没有做什 么事情,只是在连接器和容器外面多包了一层,把它们组装在一起。Tomcat内可能有多个Service,这样的设计也是出于灵活性的考虑。通过在Tomcat中配置多个 Service,可以实现通过不同的端口号来访问同一台机器上部署的不同应用。这就解释了我们可以在webapps下部署多个不同的war包了吧,因为它们归属于不同的 service啊

连接器具体的组件

在这里插入图片描述

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

EndPoint

  • EndPoint : Coyote 通信端点,即通信监听的接口,是具体Socket接收和发送处理 器,是对传输层的抽象,因此EndPoint用来实现TCP/IP协议的
  • Tomcat 并没有EndPoint 接口,而是提供了一个抽象类AbstractEndpoint , 里面定 义了两个内部类:Acceptor和SocketProcessor。Acceptor用于监听Socket连接请求。 SocketProcessor用于处理接收到的Socket请求,它实现Runnable接口,在Run方法里 调用协议处理组件Processor进行处理。为了提高处理能力,SocketProcessor被提交到 线程池来执行。而这个线程池叫作执行器(Executor),我在后面的专栏会详细介绍 Tomcat如何扩展原生的Java线程池

Processor

Coyote 协议处理接口 ,如果说EndPoint是用来实现TCP/IP协议的,那么 Processor用来实现HTTP协议,Processor接收来自EndPoint的Socket,读取字节流解 析成Tomcat Request和Response对象,并通过Adapter将其提交到容器处理, Processor是对应用层协议的抽象

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容 器,从server.xml中基本上可以猜到,servlet容器包含的主要组件

Catalina 是Servlet 容器实现,包含了之前讲到的所有的容器组件,它通过松耦合的方式集成 Coyote,以完成按照请求协议进行数据读写。同时,它还包括我们的启动入口、Shell程 序等

在这里插入图片描述
Tomcat 本质上就是一款 Servlet 容器, 因此Catalina 才是 Tomcat 的核心 , 其他模块 都是为Catalina 提供支撑的。 比如 : 通过Coyote 模块提供链接通信,Jasper 模块提供 JSP引擎,Naming 提供JNDI 服务,Juli 提供日志服务,这些从server.xml文件中可以找到对应的标签

在这里插入图片描述
如上图所示,Catalina负责管理Server,而Server表示着整个服务器。Server下面有多个 服务Service,每个服务都包含着多个连接器组件Connector(Coyote 实现)和一个容器 组件Container。在Tomcat 启动的时候, 会初始化一个Catalina的实例

Catalina 各个组件的职责:

  1. Catalina:负责解析Tomcat的配置文件 , 以此来创建服务器Server组件,并根据 命令来对其进行管理
  2. Server:服务器表示整个Catalina Servlet容器以及其它组件,负责组装并启动 Servlet引擎,Tomcat连接器。Server通过实现Lifecycle接口,提供了 一种优雅的启动和关闭整个系统的方式
  3. Service:服务是Server内部的组件,一个Server包含多个Service。它将若干个 Connector组件绑定到一个Container(Engine)上
  4. Connector:连接器,处理与客户端的通信,它负责接收客户请求,然后转给相关 的容器处理,最后向客户返回响应结果
  5. Container:容器,负责处理用户的servlet请求,并返回对象给web用户的模块
  6. Engine:表示整个Catalina的Servlet引擎,用来管理多个虚拟站点,一个Service 最多只能有一个Engine,但是一个引擎可包含多个Host
  7. Host:代表一个虚拟主机,或者说一个站点,可以给Tomcat配置多个虚拟主 机地址,而一个虚拟主机下可包含多个Context

在这里插入图片描述

  1. Context:表示一个Web应用程序, 一个Web应用可包含多个Wrapper
  2. Wrapper:表示一个Servlet,Wrapper 作为容器中的最底层,不能包含子容器

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

<Server ><Service ><Connector  /><Connector  /><Engine><Host><Context></Context></Host></Engine></Service>
</Server>

在这里插入图片描述

容器通过 Pipeline-Valve 责任链,对请求一次处理,invoke 处理方法,每个容器都有一个 Pipeline,触发第一个 Valve,这个容器的 valve 都会被调到,不同容器之间通过 Pipeline 的 getBasic 方法,负责调用下层容器的第一个 Valve

在这里插入图片描述
当然,如果想更深入的了解这些图的内涵,最好还是需要通过源码的方式进行调试,那样才能更深刻的了解其背后的原理

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/62827.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息