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版本:我的是企业版.(至于红帽 ...
随机推荐
- Linux 自定义命令
在某个用户的家目录下 的 .bashrc 文件,写入如下内容: # .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . ...
- 【Unity3D技术文档翻译】第1.0篇 AssetBundles
前言 "Unity圣典"是目前对官方文档翻译比较详细的,然而文档的最新更新日期是2013年,已经远远落后最新版本,参考意义有限.官方文档.脚本手册是学习Unity3D最直接有效的途 ...
- Python标准异常总结
Python标准异常总结 AssertionError 断言语句(assert)失败 AttributeError 尝试访问未知的对象属性 EOFError 用户输入文件末尾标志EOF(Ctrl+d ...
- Mysql(二):库操作
一 系统数据库 information_schema: 虚拟库,不占用磁盘空间,存储的是数据库启动后的一些参数,如用户表信息.列信息.权限信息.字符信息等performance_schema: MyS ...
- Jenkins系列——定时构建
1.环境说明 操作系统:win7旗舰版64bit jdk:sun JDK1.7.0_80 64bit tomcat:apache-tomcat-8.0.41 jenkins:2.32.3LST 本系列 ...
- LeetCode第五天
leetcode 第五天 2018年1月6日 22.(566) Reshape the Matrix JAVA class Solution { public int[][] matrixReshap ...
- 批标准化(Batch Norm)
BN作用: 加速收敛 控制过拟合,可以少用或不用Dropout和正则 降低网络对初始化权重不敏感 允许使用较大的学习率 一.如何加速收敛? 通过归一化输入值/隐藏单元值,以获得类似的范围值,可加速学习 ...
- POJ - 3279 枚举 [kuangbin带你飞]专题一
这题很经典啊,以前也遇到过类似的题--计蒜客 硬币翻转. 不过这题不仅要求翻转次数最少,且翻转方案的字典序也要最小. 解法:二进制枚举第一行的翻转方案,然后处理第二行,如果第二行的k列的上一列是黑色, ...
- 在SpringBoot中配置aop
前言 aop作为spring的一个强大的功能经常被使用,aop的应用场景有很多,但是实际的应用还是需要根据实际的业务来进行实现.这里就以打印日志作为例子,在SpringBoot中配置aop 已经加入我 ...
- PDO学习
参考: http://php.net/manual/zh/pdostatement.fetch.php http://php.net/manual/zh/pdo.constants.php