Tomcat最底层使用的是Java标准的SocketServer和Socket接受和处理请求,但是Socket接受到的数据是网络运输层的TCP或UDP协议的数据,需要转为Http或者其它应用层协议的数据。Tomcat中就是通过连接器Connector来管理Socket连接、解析Scoket请求为Request并封装响应数据为Response对象。新版本的Tomcat容器使用的连接器是Coyote框架,本文会详细介绍Connector的Coyote框架原理。本文很多内容参考了这篇博客

什么是Coyote

Coyote是Tomcat链接器框架的名称,是Tomcat服务器提供的供客户端访问的外部接口。客户端通过Coyote与服务器建立链接、发送请求并且接收响应。

Coyote封装了底层的网络通信(Socket请求以及响应处理),为Catalina容器提供了统一的接口,是Catalina容器与具体的请求协议以及 I/O方式解耦。Coyote将Socket输入转换为Request对象,交由Catalina容器进行处理,处理请求完成之后,Catalina通过Coyote提供的Response对象将结果写入输出流。

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

Coyote支持的协议

Coyote框架支持以下三种应用层协议:

  1. HTTP/1.1协议:这是绝大多数Web应用采用的访问协议,主要用于Tomcat单独运行(不予Web服务器集成)的情况。
  2. AJP协议:用于和Web服务器(如Apache HTTP Server)集成,以实现针对静态资源的优化以及集群部署,当前支持AJP/1.3。
  3. HTTP/2.0协议:下一代HTTP协议,自Tomcat8.5以及9.0版本开始支持,截止目前,主流的最新版本均已支持HTTP/2.0。

针对HTTP和AJP协议,Coyote又按照 I/O方式分别提供了不同的选择方案(自8.5/9.0版本起,Tomcat已出了对BIO的支持)。

  1. NIO:采用Java NIO类库实现。
  2. NIO2:采用JDK 7最新的NIO2类库实现。
  3. APR:采用APR(Apache可移植运行库)实现

在8.0之前,Tomcat默认采用的I/O方式为BIO,之后采用NIO。无论NIO、NIO2还是APR,在性能方面均优于以往的BIO。如果采用APR,甚至可以达到接近于 Apache HTTP Server的响应性能。

在Coyote中,HTTP/2.0的处理方式与HTTP/1.1和AJP不同,采用一种升级协议的方式实现,这也是有HTTP/2.0的传输方案决定的。

可以采用一种简单的分层视图来描述Tomcat对协议以及 I/O方式的支持,如下图所示:

Connector的核心概念

在Connector中有如下几个核心概念:

  • Endpoint:Coyote通信端点,即通信监听的接口,是具体的Socker接收处理类,是对传输层的抽象。Tomcat并没有Endpoint接口,而是提供了一个抽象类AvstractEndpoint。根据I/O方式的不同,提供了NioEndpoint(NIO)、AprEndpoint(APR)以及Nio2Endpoint(NIO2)三个实现。
  • Processor:Coyote协议处理接口,负责构造Request和Response对象,并且通过Adapter将其提交到Catalina容器处理,是对应用层的抽象。Processor是单线程的,Tomcat在同一次链接中复用Processor。Tomcat按照协议的不同提供了3个实现类:Http11Processor(HTTP/1.1)、AjpProcessor(AJP)、StreamProcessor(HTTP/2.0)。除此之外,他还提供了两个用于处理内部处理的实现:UpgradeProcessorInternal和UpgradeProcessorExternal,前者用于处理内部支持的升级协议(如HTTP/2.0和WebSocket),后者用于处理外部扩展的升级协议支持。
  • UpgradeProtocol:Tomcat采用UpgradeProtocol接口表示HTTP升级协议,当前只提供了一个实现(Http2Protocol)用于处理HTTP/2.0.他根据请求创建一个用于升级处理的令牌UpgradeToken,该令牌中包含了具体的HTTP升级处理器HttpUpgradeHandler,HTTP/2.0的处理器实现为Http2UpgradeHandler。Tomcat中的WebSocket也是通过UpgradeToken机制实现的。

Connector请求处理流程

Connector处理请求的流程如上所示,我们一步步分析一下流程的内容:

  1. 当Connector启动时,会同时启动其持有的Endpoint实例。Endpoint并允许多个线程(有属性acceptorThreadCount确定),每个线程允许一个AbstractEndpoint.Acceptor实例。在AbstractEndpoint.Acceptor实例中监听端口通信(I/O方式不同,具体的处理方式也不同),而且只要Endpoint处于运行状态,始终循环监听。
  2. 当监听到请求时,Acceptor将Socker封装为SocketWrapper实例(此时并未读取数据),并交由一个SocketProcessor对象处理(此过程也由线程池异步处理)。此部分根据I/O方式的不同处理会有所不同,如NIO采用轮询的方式检测SelectionKey是否就绪。如果就绪,则获取一个有效的SocketProcessor对象并且提交线程池处理。
  3. SocketProcessor是一个线程池Worker实例,每一个I/O方式均有自己的实现。他首先判断Socket的状态(如完成SSL握手),然后提交到ConnectionHandler处理。
  4. ConnectionHandler是AbstractProtocol的一个内部类,主要用于链接选择一个合适的Processor实现以进行请求处理。
    • 提升性能,他针对每个有效的理解都会缓存器Processor对象。不仅如此,当前链接关闭时,其Processor对象还会被释放到一个回收队列(升级协议不会回收),这样后续链接可以重置并且重复利用,以减少对象构造。
    • 在处理请求时,他首先会从缓存中获取当前链接的Processor对象。如果不存在,则尝试根据协商协议构造Processor(如HTTP/2.0请求)。如果不存在协商协议(如HTTP/1.1请求),则从回收队列中获取一个已释放的Processor对象使用。如果回收队列中没有可用的对象,那么由具体的协议创建一个Processor使用(同时注册到缓存)。
  5. 协议升级时,ConnectionHandler会从当前Processor得到一个UpgradeToken对象(如果没有,则默认为HTTP/2),并构造一个升级Processor实例(如果是Tomcat支持的协议则会是UpgradeProcessorInternal,否则是UpgradeProcessorExternal)替换当前的Processor,并将当前的Processor释放回收。替换后,该链接的后续处理将由升级Process完成。
  6. 通过UpgradeToken中HttpUpgradehandler对象的init()方法进行初始化,以便准备开始启用新协议。

我是御狐神,欢迎大家关注我的微信公众号:wzm2zsd

本文最先发布至微信公众号,版权所有,禁止转载!

学习Tomcat(三)之容器连接器的更多相关文章

  1. Spring学习总结三——SpringIOC容器三

    一:spring容器自动装配注入 为了减少xml中配置内容,可以使用自动装配注入,代替setter注入,只需要在 bean对象配置中添加属性autoWire即可,那么在类中就会自动扫描setXXX() ...

  2. STL学习笔记(三) 关联容器

    条款19:理解相等(equality)和等价(equivalence)的区别 相等的概念是基于 operator== 的,如果 operator== 的实现不正确,会导致并不实际相等等价关系是以&qu ...

  3. tomcat(5)servlet容器

    [0]README 0.0)本文部分文字描写叙述转自:"深入剖析tomcat",旨在学习 tomcat(5)servlet容器 的基础知识. 0.1)intro to servle ...

  4. Tomcat剖析(三):连接器(2)

    Tomcat剖析(三):连接器(2) 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三):连接器(1) 4 ...

  5. Tomcat剖析(三):连接器(1)

    Tomcat剖析(三):连接器(1) 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三):连接器(1) 4 ...

  6. JavaWeb学习总结(三)——Tomcat服务器学习和使用(二) 包含https 非对称秘钥 NB

    JavaWeb学习总结(三)--Tomcat服务器学习和使用(二) 一.打包JavaWeb应用 在Java中,使用"jar"命令来对将JavaWeb应用打包成一个War包,jar命 ...

  7. 学习Tomcat(一)之容器概览

    Tomcat是Apache软件基金会的一个顶级项目,由Apache.Sun和其它一些公司及个人共同开发,是目前比较流行的Web服务器之一.Tomcat是一个开源的.小型的轻量级应用服务器,具有占用系统 ...

  8. JSP学习笔记(三):简单的Tomcat Web服务器

    注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...

  9. JavaWeb学习总结(三)——Tomcat服务器学习和使用

    收藏 JavaWeb学习总结(三)——Tomcat服务器学习和使用 http://www.cnblogs.com/xdp-gacl/p/3744053.html

随机推荐

  1. RocketMQ原理分析&场景问题

    硬核干货分享,欢迎关注[Java补习课]成长的路上,我们一起前行 ! <高可用系列文章> 已收录在专栏,欢迎关注! 一.RocketMQ的基本原理 RocketMQ基本架构图如下 从这个架 ...

  2. putty编译过程

    在Win7上用Visual Studio编译putty源代码. 安装vs2005,只安装c++和.net framework sdk即可: 将putty-src.zip解压到e:\MyDoc\VSPr ...

  3. Python - typing 模块 —— 类型别名

    前言 typing 是在 python 3.5 才有的模块 前置学习 Python 类型提示:https://www.cnblogs.com/poloyy/p/15145380.html 常用类型提示 ...

  4. 002 PCI Express体系结构(二)

    一.PCI总线的信号定义 PCI总线是一条共享总线,在一条PCI总线上可以挂接多个PCI设备.这些PCI设备通过一系列信号与PCI总线相连,这些信号由地址/数据信号.控制信号.仲裁信号.中断信号等多种 ...

  5. java获取真实ip工具类

    场景 有的时候我们需要获取客户端的真实ip,用来实现ip白名单,和黑名单的配置! ip工具类如下 package com.meeno.framework.utils; import javax.ser ...

  6. EZpop分析

    首先源代码如下 <?php class Modifier { protected $var; public function append($value){ include($value); } ...

  7. 如何选择Spring cloud和 Spring Boot对应的版本

    如何选择Spring cloud和 Spring Boot对应的版本 首先,我们进入Spring Cloud官网,查询Spring cloud的版本和对应的Spring Boot版本 打开Spring ...

  8. js判断对象的某个属性是否存在

    参考:https://www.jb51.net/article/141994.htm 原始数据, [ {"name":"向阳镇","id": ...

  9. Qt多窗口编程详解

    常用的窗体基类是 QWidget.QDialog 和 QMainWindow,在创建 GUI 应用程序时选择窗体基类就是从这 3 个类中选择. QWidget 直接继承于 QObject,是 QDia ...

  10. 【多线程】不懂什么是 Java 中的锁?看看这篇你就明白了!

    本文来源:Java建设者 原文地址:https://mp.weixin.qq.com/s/GU42BjM5jY2CEMVD_PAZBQ Java 锁分类 Java 中的锁有很多,可以按照不同的功能.种 ...