Tomcat处理HTTP请求源码分析(下)
转载:http://www.infoq.com/cn/articles/zh-tomcat-http-request-2
很多开源应用服务器都是集成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<NioChannel>队列中。该线程数目可配置,默认为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事件。
- 在Acceptior线程中接收了客户请求(serverSock.accept())

- 委托线程池处理

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

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

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

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

4.4 Poller线程读请求、生成响应数据、注册WRITE事件
- 在上面说的setSocketOptions方法中调用Poller线程的register方法注册读事件之后,当READ准备就绪之后,就开始读了。下面代码位于Poller线程的run方法之中:

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

- 线程池的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
感谢张凯峰对本文的审校。
Tomcat处理HTTP请求源码分析(下)的更多相关文章
- Tomcat处理HTTP请求源码分析(上)
Tomcat处理HTTP请求源码分析(上) 作者 张华 发布于 2011年12月8日 | 8 讨论 分享到: 微博 微信 Facebook Twitter 有道云笔记 邮件分享 稍后阅读 我的阅读清单 ...
- Tomcat处理HTTP请求源码分析(上)(转)
转载自:http://www.infoq.com/cn/articles/zh-tomcat-http-request-1 很多开源应用服务器都是集成tomcat作为web container的,而且 ...
- 知识小罐头07(tomcat8请求源码分析 下)
感觉最近想偷懒了,哎,强迫自己也要写点东西,偷懒可是会上瘾的,嘿嘿!一有写博客的想法要赶紧行动起来,养成良好的习惯. ok,继续上一篇所说的一些东西,上一篇说到Connector包装了那两个对象,最后 ...
- # Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析#
Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析 Volley源码一共40多个类和接口.除去一些工具类的实现,核心代码只有20多个类.所以相对来说分析起来没有那么吃力.但是要想分析透 ...
- 知识小罐头06(tomcat8请求源码分析 中)
更正上一篇一个小错误,Connector中首先是将socket请求过来的信息封装成一个普通的Request对象(上一篇我写成HttpRequest对象,失误失误,根本就木有HttpRequest这样的 ...
- Okhttp同步请求源码分析
进阶android,OKhttp源码分析——同步请求的源码分析 OKhttp是我们经常用到的框架,作为开发者们,我们不单单要学会灵活使用,还要知道他的源码是如何设计的. 今天我们来分析一下OKhttp ...
- 详解Tomcat系列(一)-从源码分析Tomcat的启动
在整个Tomcat系列文章讲解之前, 我想说的是虽然整个Tomcat体系比较复杂, 但是Tomcat中的代码并不难读, 只要认真花点功夫, 一定能啃下来. 由于篇幅的原因, 很难把Tomcat所有的知 ...
- 【MyBatis】MyBatis Tomcat JNDI原理及源码分析
一. Tomcat JNDI JNDI(java nameing and drectory interface),是一组在Java应用中访问命名和服务的API,所谓命名服务,即将对象和名称联系起来,使 ...
- 知识小罐头05(tomcat8请求源码分析 上)
这一篇我们不看源码,就大概理一下Tomcat内部组成部分!前面花费了两篇博客的篇幅来说说了一般的maven web项目并部署到tomcat运行,其实都是为这篇做铺垫的! 其实我下载了tomcat7,t ...
随机推荐
- C++安装失败解决办法
法一:删除注册表中的HKY_LOCAL_MACHINE\\SYSTEM|ControlSet001\\Services\\VSS,卸载重装.法二:点击 setup目录下的 wpie15.exe .. ...
- PHP+AJAX无刷新返回天气预报
AjaxJavaScript天气预报php天气预报,用php来写一个天气预报的模块. 天气数据是通过采集中国气象网站的.本来中国天气网站也给出了数据的API接口.以下是API的地址.返回的数据格式为j ...
- WordPress 主题开发 - (五)WordPress 主题模板及目录结构 待翻译
While the most minimal of WordPress Themes really only need an index.php template and a style.css fi ...
- mercurial(hg)使用
# 版本管理软件的比较 svn 每个目录下建一个.svn目录实在是不爽. git 分支管理非常方便,但没感觉有什么用,主要还是在修改前提交一次代码, 等后悔时再回来,没什么其他的目的.关键是中文乱码问 ...
- VC Dimension -衡量模型与样本的复杂度
(1)定义VC Dimension: dichotomies数量的上限是成长函数,成长函数的上限是边界函数: 所以VC Bound可以改写成: 下面我们定义VC Dimension: 对于某个备选函数 ...
- Ztack学习笔记(2)-系统初始化分析
main函数先执行初始化工作,包括硬件.网络层.任务等的初始化. 一 系统初始化 系统初始化函数主要完成内存分配.消息队列头.定时器.电源管理.任务系统及内存栈等的初始化,具体如下代码所示: //os ...
- WPF:简洁为美
(1)3行代码实现水印TextBox(Watermark TextBox) 效果图: 源代码: <Grid> <Grid.Resources> <BooleanToVi ...
- Java String.split()注意点
//String[] aa = "aaa|bbb|ccc".split("|");//错误 String[] aa = "aaa|bbb|ccc&qu ...
- 单例模式(Singleton)的6种实现
1.1.1 摘要 在我们日常的工作中经常需要在应用程序中保持一个唯一的实例,如:IO处理,数据库操作等,由于这些对象都要占用重要的系统资源,所以我们必须限制这些实例的创建或始终使用一个公用的实例,这就 ...
- 【学习总结】【多线程】 安全隐患 & 通讯 & 线程的状态
一.多线程的安全隐患 资源共享 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块资源时,很容易引发数据错乱和数 ...
