QCon全球软件开发大会8折优惠倒计时,购票立减¥1760!了解详情 >>> 了解详情
写点什么

Tomcat 处理 HTTP 请求源码分析(下)

2011 年 12 月 16 日

很多开源应用服务器都是集成 tomcat 作为 web container 的,而且对于 tomcat 的 servlet container 这部分代码很少改动。这样,这些应用服务器的性能基本上就取决于 Tomcat 处理 HTTP 请求的 connector 模块的性能。本文首先从应用层次分析了 tomcat 所有的 connector 种类及用法,接着从架构上分析了 connector 模块在整个 tomcat 中所处的位置,最后对 connector 做了详细的源代码分析。并且我们以 Http11NioProtocol 为例详细说明了 tomcat 是如何通过实现 ProtocolHandler 接口而构建 connector 的。

上篇地址为《 Tomcat 处理 HTTP 请求源码分析(上)》 ,本文是系列下篇。

4 如何实现 Connector

由上面的介绍我们可以知道,实现 Connector 就是实现 ProtocolHander 接口的过程。

AjpAprProtocol、AjpProtocol、Http11AprProtocol、Http11Protocol、JkCoyoteHandler、MemoryProtocolHandler 这些实现类的实现流程与 Http11NioProtocol 相同,下面我们以 Http11NioProtocol 为类重点说明 tomcat 中如何实现 ProtocolHander 接口的。

Http11NioProtocol 实现了 ProtocolHander 接口,它将所有的操作委托给 NioEndpoint 类去做,如下图:

NioEndpoint 类中的 init 方法中首先以普通阻塞方式启动了 SocketServer:

NioEndpoint 类的 start 方法是关键,如下:

可以看出,在 start 方法中启动了两个线程和一个线程池:

  • Acceptor 线程,该线程以普通阻塞方式接收客户端请求(socket.accep()),将客户 Socket 交由线程池是处理,线程池要将该 Socket 配置成非阻塞模式(socket.configureBlocking(false)), 并且向 Selector 注册 READ 事件。该线程数目可配置,默认为 1 个。
  • Poller 线程,由于 Acceptor 委托线程为客户端 Socket 注册了 READ 事件,当 READ 准备好时,就会进入 Poller 线程的循环,Poller 线程也是委托线程池去做,线程池将 NioChannel 加入到 ConcurrentLinkedQueue队列中。该线程数目可配置,默认为 1 个。
  • 线程池,就是上面说的做 Acceptor 与 Poller 线程委托要做的事情。

4.1 Init 接口实现方法中阻塞方式启动 ServerSocketChannel

在 Init 接口实现方法中阻塞方式启动 ServerSocketChannel。

4.2 Start 接口实现方法中启动所有线程

Start 方法中启动了线程池,acceptor 线程与 Poller 线程。其中 acceptor 与 poller 线程一般数目为 1,当然,数目也可配置。

可以看出,线程池有两种实现方式:

  • 普通 queue + wait + notify 方式,默认使用的方式,据说实际测试这种比下种效率高
  • JDK1.5 自带的线程池方式

4.3 Acceptor 线程接收客户请求、注册 READ 事件

在 Acceptor 线程中接收了客户请求,同时委托线程池注册 READ 事件。

  1. 在 Acceptior 线程中接收了客户请求(serverSock.accept())

  2. 委托线程池处理

  3. 在线程池的 Worker 线程的 run 方法中有这么几句:

在 setSocketOptions 方法中,首先将 socket 配置成非阻塞模式:

在 setSocketOptions 方法中,最后调用 getPoller0().register(channel); 一句为 SocketChannel 注册 READ 事件,register 方法代码如下 (注意:这是 Poller 线程的方法):

其中 attachment 的结构如下,它可以看做是一个共享的数据结构:

4.4 Poller 线程读请求、生成响应数据、注册 WRITE 事件

  1. 在上面说的 setSocketOptions 方法中调用 Poller 线程的 register 方法注册读事件之后,当 READ 准备就绪之后,就开始读了。下面代码位于 Poller 线程的 run 方法之中:

  2. 可以看到,可读之后调用 processSocket 方法,该方法将读处理操作委拖给线程池处理 (注意此时加入到线程池的是 NioChannel,不是 SocketChannel):

  3. 线程池的 Worker 线程中的 run 方法中的部分代码如下(请注意 handler.process(socket) 这一句):

注意:

  • 调用了 hanler.process(socket) 来生成响应数据)
  • 数据生成完之后,注册 WRITE 事件的,代码如下:

4.5 Handle 接口实现类通过 Adpater 调用 Servlet 容器生成响应数据

NioEndpoint 类中的 Handler 接口定义如下:

其中 process 方法通过 Adapter 来调用 Servlet Container 生成返回结果。Adapter 接口定义如下:

4.6 小结

实现一个 tomcat 连接器 Connector 就是实现 ProtocolHander 接口的过程。Connector 用来接收 Socket Client 端的请求,通过内置的线程池去调用 Servlet Container 生成响应结果,并将响应结果同步或异步的返回给 Socket Client。在第三方应用集成 tomcat 作为 Web 容器时,一般不会动 Servlet Container 端的代码,那么 connector 的性能将是整个 Web 容器性能的关键。

关于作者

张华,长期从事 Java 方面的开发工作,有搜索引擎、中间件应用服务器、互联网、云计算等领域的行业经验,目前正在从事基于 Power 的虚拟化技术研发。博客地址: http://blog.csdn.net/quqi99


感谢张凯峰对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2011 年 12 月 16 日 00:0013289

评论

发布
暂无评论
发现更多内容

代码整洁之道

田维常

代码

Kube-OVN再更新! v0.8.0 支持网关高可用以及网络监控集成

York

灵雀云 Kubernetes k8s Kube-OVN

灵雀云开源项目 Kube-OVN 亮相开源基础设施峰会

York

灵雀云 Kubernetes k8s Kube-OVN

中国特色新基建可视化,工程监控画面还能这么美?你绝对没见过

一只数据鲸鱼

物联网 新基建 数据可视化 绿色工业

腾讯大佬亲自总结出“Java知识地图+学习路线”从点到面一应俱全!不看血亏

比伯

Java 编程 架构 程序人生 计算机

云算力矿机租赁挖矿APP系统开发|云算力矿机租赁挖矿软件开发

开發I852946OIIO

系统开发

Java中定时器Timer致命缺点(附学习方法)

叫练

定时任务 高效学习 多线程 定时器 技术学习

软件界旷世之架:测试驱动开发(TDD)之争

华为云开发者社区

软件 测试 TDD 代码 devcloud

一份阿里Java学习路线出现“病毒式”传播,导致44人秋招同时拿到offer

Java架构师迁哥

Kube-OVN v 0.7.0 发布,IPAM、子网和安全功能增强

York

灵雀云 Kubernetes k8s Kube-OVN

Kube-OVN v0.9.0更新,网络可视化和控制平面稳定性提升

York

灵雀云 Kubernetes k8s Kube-OVN

新思科技网络安全研究中心发现Bouncy Castle中的漏洞

InfoQ_434670063458

新思科技 Bouncy Castle

SpringCloud从入门到精通01---父项目创建

Felix

SpringCloud Eureka 高可用架构

技术实录 | 灵雀云基于 OVN 的 Kubernetes 网络架构解析

York

灵雀云 Kubernetes k8s Kube-OVN

大作业一:架构设计方案评审

Nick~毓

一个20年技术老兵的 2020 年度技术总结

万俊峰Kevin

go 微服务 微服务治理 go-zero 微服务框架

软件测试--缺陷报告

测试人生路

软件测试

Kube-OVN 0.6.0 发布,支持 IPv6、流量镜像及更多功能

York

灵雀云 Kubernetes k8s Kube-OVN

“持证”就能上岗 京东绿色内推招聘通道开启

京东科技开发者

云计算 大数据 程序人生

Python进阶系列文章汇总

Kaito

Python 爬虫

同城快递系统-大作业

三板斧

极客时间架构师一期

价值 - 价值的底色(一)

石云升

读书笔记 投资 28天写作 价值

灵雀云Kube-OVN:基于OVN的开源Kubernetes网络实践

York

灵雀云 Kubernetes k8s Kube-OVN

再谈自研开源Kube-OVN, 设计思路及实现原理

York

灵雀云 Kubernetes k8s Kube-OVN

OVS 设计与实现阅读笔记,五年前的这篇论文里这些问题已经明了

York

Kubernetes k8s Kube-OVN

SpringCloud从入门到精通02---支付模块01

Felix

Yarn RM写ZNode超数据量限制bug修复

笨小康

大数据 zookeeper YARN

教小师妹快速入门Maven,嘿嘿嘿...

田维常

maven

Hive的调优你都知道那些?

大数据老哥

大数据 hadoop hive

Kube-OVN 0.5.0 发布,支持 NetworkPolicy、用户自定义网卡和MTU

York

灵雀云 Kubernetes k8s Kube-OVN

架构师训练营技术知识点

三板斧

架构师训练营第 1 期

移动应用开发的下一站

移动应用开发的下一站

Tomcat处理HTTP请求源码分析(下)-InfoQ