6张图说清楚Tomcat原理及请求流程
- 绘制图形使用的工具是 PlantUML + Visual Studio Code + PlantUML Extension

- Overview
- Connector Init and Start
- Requtst Process
- Acceptor
- Poller
- Worker
- Container
- At last

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

- 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 对其进行定制。

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

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

- 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 线程中执行的,但是这是一个相对独立的模块,所以单独分出来一节。

- 需要注意的是,基本上每一个容器的 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() 方法。
- 《How Tomcat works》
- 《Tomcat 架构解析》-- 刘光瑞
- Tomcat-9.0-doc
- apache-tomcat-9.0.0.M22-src
- tomcat 架构分析 (connector NIO 实现)
6张图说清楚Tomcat原理及请求流程的更多相关文章
- TOMCAT原理详解及请求过程(转载)
转自https://www.cnblogs.com/hggen/p/6264475.html TOMCAT原理详解及请求过程 Tomcat: Tomcat是一个JSP/Servlet容器.其作为Ser ...
- Tomcat 原理篇
TOMCAT 原理篇一.Tomcat 组成(Tomcat 由以下组件组成) 1.server a) Server是一个Catalina Servlet容器: b) Server 可以包含一个或多个se ...
- 【第十一课】Tomcat原理解析【转】
目录 一.Tomcat顶层架构 二.Tomcat顶层架构小结: 三.Connector和Container的微妙关系 四.Connector架构分析 五.Container架构分析 六.Contain ...
- tomcat原理解析(一):一个简单的实现
tomcat原理解析(一):一个简单的实现 https://blog.csdn.net/qiangcai/article/details/60583330 2017年03月07日 09:54:27 逆 ...
- tomcat原理分析与简单实现
tomcat原理分析与简单实现 https://blog.csdn.net/u014795347/article/details/52328221 2016年08月26日 14:48:18 卫卫羊习习 ...
- 走进JavaWeb技术世界5:初探Tomcat的HTTP请求过程
初探Tomcat的HTTP请求过程 前言:1.作为Java开发人员,大多都对Tomcat不陌生,由Apache基金会提供技术支持与维护,因为其免费开源且易用,作为Web服务器深受市场欢迎,所以有必要对 ...
- 《浏览器工作原理与实践》<03>HTTP请求流程:为什么很多站点第二次打开速度会很快?
一个 TCP 连接过程包括了建立连接.传输数据和断开连接三个阶段. 而 HTTP 协议,正是建立在 TCP 连接基础之上的.HTTP 是一种允许浏览器向服务器获取资源的协议,是 Web 的基础,通常由 ...
- tomcat跨域请求
tomcat A请求tomcat B中的数据(本人是在同一台机器上2个tomcat端口不同,在不同机器上有时间会测得) 博主用的是ajax请求 在A 请求B中数据,用下面的方法可以 在被请求的tomc ...
- Tomcat处理HTTP请求源码分析(下)
转载:http://www.infoq.com/cn/articles/zh-tomcat-http-request-2 很多开源应用服务器都是集成tomcat作为web container的,而且对 ...
随机推荐
- sqlcipher的php扩展运行在fast-cgi:php-fpm下工作不正常
今天发现了这样的问题,php-fpm运行sqlcipher时,有些数据库工作正常,有些却不正常. 不正常的,都在日志上报错,也就是php处理异常了. 这个报错发生在执行sql语句时,通常就是sqlci ...
- React-Hook
import React, { useState } from 'react'; // Hook 写法 function App2 () { const [count,setCount] = useS ...
- Android DecorView 与 Activity 绑定原理分析
一年多以前,曾经以为自己对 View 的绘制已经有了解了,事后发现也只是懂了些皮毛而已.经过一年多的实战,Android 和 Java 基础都有了提升,时机成熟了,是时候该去总结 View 的绘制流程 ...
- windows 10上源码编译libjpeg-turbo和使用教程 | compile and use libjpeg-turbo on windows 10
本文首发于个人博客https://kezunlin.me/post/83828674/,欢迎阅读! compile and use libjpeg-turbo on windows 10 Series ...
- 协议分层(因特网5层模型)及7层OSI参考模型
目录 因特网5层模型及7层OSI参考模型 分层的体系结构: 应用层(软件) 运输层(软件) 网络层(硬件软件混合) 链路层(硬件) 物理层(硬件) OSI模型 表示层 会话层 封装 因特网5层模型及7 ...
- Java流程控制之(一)条件
目录 条件语句 单if情况 单if/else情况 if/else多分支情况 switch条件语句 条件语句+循环语句,直接甩图甩代码! 条件语句 Java希望在某个条件为真时执行相应的语句. 单if情 ...
- 【Luogu P2471】[SCOI2007]降雨量
Luogu P2471 啊啊啊啊这真是一道史上最毒瘤的题目!!!!! 题意就是给出n个年份的降雨量 询问:"自从\(y\)年以来\(x\)年的降雨量最大"的正确性. 显然有多种情况 ...
- 图解 Spring:HTTP 请求的处理流程与机制【2】
2. HTTP 请求在 Web 容器中的处理流程 Web 容器以进程的方式在计算机上运行,我们知道进程是系统资源分配的最小单元,线程是系统任务执行的最小单元.从这个角度看,Web 容器就像是邮包收件人 ...
- MYSQL远程连接速度慢的解决方法
在局域网内连接其他机器的MYSQL,发现速度慢的很,不知道什么原因,总有几秒的延迟. 后来在网上发现解决方法,my.ini里面添加 [mysqld]skip-name-resolveskip-gran ...
- C语言博客作业08
C语言I博客作业08](https://www.cnblogs.com/490-85-00-58-/p/11863312.html) 问题 回答 这个作业属于那个课程 C语言程序设计II 这个作业要求 ...