Tomcat与Jetty底层拆解(一)

目录

1.Web容器

2.Servlet规范与Servlet容器

2.1 Servlet和Servlet容器是什么

2.2 Servlet接口实现解耦和

2.3 Servlet容器

3.Tomcat架构设计之连接器

3.1 Tomcat支持的I/O模型

3.2 Tomcat支持的应用层协议

3.3 Tomcat连接器

3.4 Tomcat链接器组件之Endpoint

3.5 Tomcat连接器组件之Processor

3.6 Tomcat连接器组件之Adapter


1.Web容器

Tomcat和Jetty本质上就是一个web容器,具体的来说就是Http服务器+Servlet容器。

随着微服务架构的日趋流行,一个大而全的单体应用程序往往被拆解成多个功能单一的微服务,为了减少资源的消耗、降低部署的成本,技术人员们希望web容器能够嵌入到web应用程序中的一部分,而不是再像以往一样通过web容器来逐一部署和启动web应用。

因此轻量级的 Tomcat 和 Jetty 就是一个很好的选择,并且 Tomcat 它本身也是 Spring Boot 默认的嵌入式 Servlet 容器。最新版本 Tomcat 和 Jetty 都支持 Servlet 4.0 规范

2.Servlet规范与Servlet容器

2.1 Servlet和Servlet容器是什么

为了实现解耦,采用每个业务类实现Sevlet接口的方式,通过模版方法模式的思路,在这个Servlet中具体定义业务处理的逻辑,从而和服务器代码进行解耦(面向接口编程的思想)。

但是这还没解决如何根据不同http请求进行分发处理的麻烦,具体点说就是:对于特定的请求,HTTP 服务器如何知道由哪个 Servlet 来处理呢?Servlet 又是由谁来实例化呢?显然 HTTP 服务器不适合做这个工作,否则又和业务类耦合了。于是Servlet容器就诞生了,它被设计用来加载和管理servlet,HTTP服务器不直接与业务类接触,而是把请求交给容器,由容器转发给具体的servlet,sevlet被加载和具体实力话,然后调用接口方法,进行http请求的处理。

 

2.2 Servlet接口实现解耦和

public interface Servlet {    
  void init(ServletConfig config) throws ServletException;        
  ServletConfig getServletConfig();        
  void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;        
  String getServletInfo();       
  void destroy();
 }

service 方法,具体业务类在这个方法里实现处理逻辑。这个方法有两个参数:ServletRequest 和 ServletResponse。ServletRequest 用来封装请求信息,ServletResponse 用来封装响应信息。具体的比如 HTTP 协议中对应了 HttpServletRequest 和 HttpServletResponse 这两个类。可以通过 HttpServletRequest 来获取所有请求相关的信息,包括请求路径、Cookie、HTTP 头、请求参数等。还可以通过 HttpServletRequest 来创建和获取 Session。而 HttpServletResponse 是用来封装 HTTP 响应的。

init 和 destroy是跟生命周期有关的方法,Servlet 容器在加载 Servlet 类的时候会调用 init 方法,在卸载的时候会调用 destroy 方法。

我们可能会在 init 方法里初始化一些资源,并在 destroy 方法里释放这些资源,比如 Spring MVC 中的 DispatcherServlet,就是在 init 方法里创建了自己的 Spring 容器。

ServletConfig 这个类,ServletConfig 的作用就是封装 Servlet 的初始化参数。可以在web.xml给 Servlet 配置参数,并在程序里通过 getServletConfig 方法拿到这些参数。

有接口一般就有抽象类,抽象类用来实现接口和封装通用的逻辑,因此 Servlet 规范提供了 GenericServlet 抽象类,我们可以通过扩展它来实现 Servlet。虽然 Servlet 规范并不在乎通信协议是什么,但是大多数的 Servlet 都是在 HTTP 环境中处理的,因此 Servet 规范还提供了 HttpServlet 来继承 GenericServlet,并且加入了 HTTP 特性。这样我们通过继承 HttpServlet 类来实现自己的 Servlet,只需要重写两个方法:doGet 和 doPost。

2.3 Servlet容器

HTTP请求并不直接调用servlet,而是通过讲请求交给sevlet容器,由servlet负责讲请求交给servlet。具体来说,servlet的工作流程如下:

当客户请求某个资源时,HTTP 服务器会用一个 ServletRequest 对象把客户的请求信息封装起来;

然后调用 Servlet 容器的 service 方法,Servlet 容器拿到请求后,根据请求的 URL 和 Servlet 的映射关系,找到相应的 Servlet;

如果 Servlet 还没有被加载,就用反射机制创建这个 Servlet,并调用 Servlet 的 init 方法来完成初始化;

接着调用 Servlet 的 service 方法来处理请求,把 ServletResponse 对象返回给 HTTP 服务器,HTTP 服务器会把响应发送给客户端。

3.Tomcat架构设计之连接器

Tomat的主要功能

  • 处理socket,负责网络字节流与Request/Response对象的转换

  • 加载和管理servlet,以及具体处理Request请求

Tomcat两大核心组件分别是连接器、容器。

3.1 Tomcat支持的I/O模型

分别支持NIO(非阻塞I/O)、NIO.2(异步式IO)以及APR(C/C++编写的本地库)

3.2 Tomcat支持的应用层协议

HTTP/1.1:这是大部分 Web 应用采用的访问协议。

AJP:用于和 Web 服务器集成(如 Apache)。

HTTP/2:HTTP 2.0 大幅度的提升了 Web 性能。

面对多样的I/O模型和应用层协议之间的组合,Tomcat将EndPoint和Processor抽象称为ProtocolHandler接口,通过实现继承相应的抽象方法,在各自的

子类中进行具体实现,从而实现了处理不同的I/O通信和应用层协议。

 

 

因为Tomcat支持了多种I/O模型和应用层协议,这就需要不同的链接器来完成工作,也就是说一个容器对应了多个连接器。

连接器和容器组合在一起称为Service

(最顶层的是server,一个server只是将多个service进行封装,server就是Tomcat的一个实例) 

3.3 Tomcat连接器

链接器对容器起到了屏蔽IO模型、应用层协议差异的作用,无论什么样的协议请求,经过连接器处理都被转化为一个标准的ServletRequesr请求对象。

主要功能为:

 

总的来说,就是完成三个动作:1.网络通信 2.应用层协议解析 3.Tomcat Request/Response与ServletRequest/ServletResponse的转换。

 

三个组件之间是通过抽象接口来进行交互的。

由于 I/O 模型和应用层协议可以自由组合,比如 NIO + HTTP 或者 NIO.2 + AJP。Tomcat 的设计者将网络通信和应用层协议解析放在一起考虑,

设计了一个叫 ProtocolHandler 的接口来封装这两种变化点。各种协议和通信模型的组合有相应的具体实现类。比如:Http11NioProtocol 和 AjpNioProtocol。

3.4 Tomcat链接器组件之Endpoint

通信监听的接口,负责Socket的接受和发送,可以认为是传输层(实现TC/IP协议)的抽象,Endpoint是接口,有两个重要的子组件——Acceptor和SocketProcessor

Accepter用于监听Socket链接请求,SocketProcessor负责处理接受到的Socket链接请求,实现Runnable接口,在run()方法中调用处理组件Processor进行处理。

3.5 Tomcat连接器组件之Processor

那么 Processor 用来实现 HTTP 协议,Processor 接收来自 Endpoint 的 Socket,读取字节流解析成 Tomcat Request 和 Response 对象,

并通过 Adapter 将其提交到容器处理,Processor 是对应用层协议的抽象。

 

 

3.6 Tomcat连接器组件之Adapter

Tomcat 定义了自己的 Request 类来“存放”这些请求信息。ProtocolHandler 接口负责解析请求并生成 Tomcat Request 类。

但是这个 Request 对象不是标准的 ServletRequest,也就意味着,不能用 Tomcat Request 作为参数来调用容器。

Tomcat 设计者的解决方案是引入 CoyoteAdapter,这是适配器模式的经典运用,连接器调用 CoyoteAdapter 的 sevice 方法,

传入的是 Tomcat Request 对象,CoyoteAdapter 负责将 Tomcat Request 转成 ServletRequest,再调用容器的 service 方法

适配器模式:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值