Tomcat 请求处理流程详解
Overview

- Connector 启动以后会启动一组线程用于不同阶段的请求处理过程。
Acceptor线程组。用于接受新连接,并将新连接封装一下,选择一个Poller将新连接添加到Poller的事件队列中。Poller线程组。用于监听 Socket 事件,当 Socket 可读或可写等等时,将 Socket 封装一下添加到worker线程池的任务队列中。worker线程组。用于对请求进行处理,包括分析请求报文并创建 Request 对象,调用容器的 pipeline 进行处理。
Acceptor、Poller、worker所在的ThreadPoolExecutor都维护在NioEndpoint中。
Connector Init and Start

initServerSocket(),通过ServerSocketChannel.open()打开一个 ServerSocket,默认绑定到 8080 端口,默认的连接等待队列长度是 100, 当超过 100 个时会拒绝服务。我们可以通过配置conf/server.xml中Connector的acceptCount属性对其进行定制。createExecutor()用于创建Worker线程池。默认会启动 10 个Worker线程,Tomcat 处理请求过程中,Woker 最多不超过 200 个。我们可以通过配置conf/server.xml中Connector的minSpareThreads和maxThreads对这两个属性进行定制。Pollor用于检测已就绪的 Socket。 默认最多不超过 2 个,Math.min(2,Runtime.getRuntime().availableProcessors());。我们可以通过配置pollerThreadCount来定制。Acceptor用于接受新连接。默认是 1 个。我们可以通过配置acceptorThreadCount对其进行定制。
Requtst Process
Acceptor

Acceptor在启动后会阻塞在ServerSocketChannel.accept();方法处,当有新连接到达时,该方法返回一个SocketChannel。- 配置完 Socket 以后将 Socket 封装到
NioChannel中,并注册到Poller,值的一提的是,我们一开始就启动了多个Poller线程,注册的时候,连接是公平的分配到每个Poller的。NioEndpoint维护了一个Poller数组,当一个连接分配给pollers[index]时,下一个连接就会分配给pollers[(index+1)%pollers.length]. addEvent()方法会将 Socket 添加到该Poller的PollerEvent队列中。到此Acceptor的任务就完成了。
Poller

selector.select(1000)。当Poller启动后因为 selector 中并没有已注册的Channel,所以当执行到该方法时只能阻塞。所有的Poller共用一个 Selector,其实现类是sun.nio.ch.EPollSelectorImplevents()方法会将通过addEvent()方法添加到事件队列中的 Socket 注册到EPollSelectorImpl,当 Socket 可读时,Poller才对其进行处理createSocketProcessor()方法将 Socket 封装到SocketProcessor中,SocketProcessor实现了Runnable接口。worker线程通过调用其run()方法来对 Socket 进行处理。execute(SocketProcessor)方法将SocketProcessor提交到线程池,放入线程池的workQueue中。workQueue是BlockingQueue的实例。到此Poller的任务就完成了。
Worker

worker线程被创建以后就执行ThreadPoolExecutor的runWorker()方法,试图从workQueue中取待处理任务,但是一开始workQueue是空的,所以worker线程会阻塞在workQueue.take()方法。- 当新任务添加到
workQueue后,workQueue.take()方法会返回一个Runnable,通常是SocketProcessor,然后worker线程调用SocketProcessor的run()方法对 Socket 进行处理。 createProcessor()会创建一个Http11Processor, 它用来解析 Socket,将 Socket 中的内容封装到Request中。注意这个Request是临时使用的一个类,它的全类名是org.apache.coyote.Request,postParseRequest()方法封装一下 Request,并处理一下映射关系(从 URL 映射到相应的Host、Context、Wrapper)。
CoyoteAdapter将 Rquest 提交给Container处理之前,并将org.apache.coyote.Request封装到org.apache.catalina.connector.Request,传递给Container处理的 Request 是org.apache.catalina.connector.Request。connector.getService().getMapper().map(),用来在Mapper中查询 URL 的映射关系。映射关系会保留到org.apache.catalina.connector.Request中,Container处理阶段request.getHost()是使用的就是这个阶段查询到的映射主机,以此类推request.getContext()、request.getWrapper()都是。
connector.getService().getContainer().getPipeline().getFirst().invoke()会将请求传递到Container处理,当然了Container处理也是在Worker线程中执行的,但是这是一个相对独立的模块,所以单独分出来一节。
Container

- 需要注意的是,基本上每一个容器的
StandardPipeline上都会有多个已注册的Valve,我们只关注每个容器的 Basic Valve。其他 Valve 都是在 Basic Valve 前执行。 request.getHost().getPipeline().getFirst().invoke()先获取对应的StandardHost,并执行其 pipeline。request.getContext().getPipeline().getFirst().invoke()先获取对应的StandardContext,并执行其 pipeline。request.getWrapper().getPipeline().getFirst().invoke()先获取对应的StandardWrapper,并执行其 pipeline。- 最值得说的就是
StandardWrapper的 Basic Valve,StandardWrapperValve
allocate()用来加载并初始化Servlet,值的一提的是 Servlet 并不都是单例的,当 Servlet 实现了SingleThreadModel接口后,StandardWrapper会维护一组 Servlet 实例,这是享元模式。当然了SingleThreadModel在 Servlet 2.4 以后就弃用了。createFilterChain()方法会从StandardContext中获取到所有的过滤器,然后将匹配 Request URL 的所有过滤器挑选出来添加到filterChain中。doFilter()执行过滤链,当所有的过滤器都执行完毕后调用 Servlet 的service()方法。
Tomcat 请求处理流程详解的更多相关文章
- Java Struts2 的请求处理流程详解
一.Struts2的处理流程: 客户端产生一个HttpServletRequest的请求,该请求被提交到一系列的标准过滤器(Filter)组建链中(如ActionContextCleanUp:它主要是 ...
- Spring mvc请求处理流程详解(一)之视图解析
本文链接:https://blog.csdn.net/lchpersonal521/article/details/53112728 前言 Spring mvc框架相信很多人都很熟悉了,关于这方面 ...
- tomcat常用配置详解和优化方法
tomcat常用配置详解和优化方法 参考: http://blog.csdn.net/zj52hm/article/details/51980194 http://blog.csdn.net/wuli ...
- 解析Tomcat之HttpServlet详解
解析Tomcat之HttpServlet详解 Servlet的框架是 由两个Java包组成:javax.servlet和javax.servlet.http. 在javax.servlet包中定义了所 ...
- C++的性能C#的产能?! - .Net Native 系列《二》:.NET Native开发流程详解
之前一文<c++的性能, c#的产能?!鱼和熊掌可以兼得,.NET NATIVE初窥> 获得很多朋友支持和鼓励,也更让我坚定做这项技术的推广者,希望能让更多的朋友了解这项技术,于是先从官方 ...
- [nRF51822] 5、 霸屏了——详解nRF51 SDK中的GPIOTE(从GPIO电平变化到产生中断事件的流程详解)
:由于在大多数情况下GPIO的状态变化都会触发应用程序执行一些动作.为了方便nRF51官方把该流程封装成了GPIOTE,全称:The GPIO Tasks and Events (GPIOTE) . ...
- 迅为4412开发板Linux驱动教程——总线_设备_驱动注册流程详解
本文转自:http://www.topeetboard.com 视频下载地址: 驱动注册:http://pan.baidu.com/s/1i34HcDB 设备注册:http://pan.baidu.c ...
- tomcat的配置详解:[1]tomcat绑定域名
转自:http://jingyan.baidu.com/article/7e440953dc096e2fc0e2ef1a.html tomcat的配置详解:[1]tomcat绑定域名分步阅读 在jav ...
- Linux下tomcat的安装详解
Linux下tomcat的安装详解 来源: ChinaUnix博客 日期: 2007.01.21 22:59 (共有0条评论) 我要评论 一,安装前的准备:1,Linux版本:我的是企业版.(至于红帽 ...
随机推荐
- mysql sql_cache缓存使用
有如下规则,如果数据表被更改,那么和这个数据表相关的全部Cache全部都会无效,并删除之.这里"数据表更改"包括: INSERT, UPDATE, DELETE, TRUNCATE ...
- Java经典编程题50道之十五
输入三个整数x,y,z,请把这三个数由小到大输出. public class Example15 { public static void main(String[] args) { ...
- 菜鸟之旅——.NET垃圾回收机制
.NET的垃圾回收机制是一个非常强大的功能,尽管我们很少主动使用,但它一直在默默的在后台运行,我们仍需要意识到它的存在,了解它,做出更高效的.NET应用程序:下面我分享一下我对于垃圾回收机制(GC)的 ...
- bzoj 2120 带修改莫队
2120: 数颜色 Time Limit: 6 Sec Memory Limit: 259 MBSubmit: 7340 Solved: 2982[Submit][Status][Discuss] ...
- C语言_结构体变量指针做函数参数的使用案例
# include <stdio.h> # include <stdlib.h> # include <string.h> # include <malloc ...
- iOS实现从服务器请求json数据并转化成NSDictionary
NSURL *url = [NSURL URLWithString:URL]; NSURLRequest *request = [NSURLRequest requestWithURL:url cac ...
- Java集合框架(五)—— Map、HashMap、Hashtable、Properties、SortedMap、TreeMap、WeakHashMap、IdentityHashMap、EnumMap
Map Map用于保存具有映射关系的数据,因此Map集合里保存着两组值,一组值用于保存Map里的key,另一组值用于保存Map里的value,key和value都可以是任何引用类型的数据.Map的ke ...
- qt Multimedia 模块类如何使用?
qt 多媒体模块介绍 类名 英文描述 中文描述 QAudioBuffer Represents a collection of audio samples with a specific format ...
- 《python机器学习—预测分析核心算法》笔记1
参见原书 1.1-1.4节 一.惩罚线性回归模型 基本特性: 1.训练时间快,使用训练好的模型进行预测的时间也快2.应用于高速交易.互联网广告的植入等3.解决回归.分类问题 最重要的特性:能明确指出, ...
- ARM-LINUX自动采集温湿度传感器数据
开机root自动登录 如果想在超级终端输入回车,登录后执行,则可以在/etc/profile中加入命令: 如果实现开机自动登录,在/etc/inittab中修改,每个开发板修改的方式可能都不同. ht ...