Tomcat-启动流程和http请求流程
分析并总结了tomcat的启动流程和整个http请求流程,重点可关注启动流程的UML图和请求流程图
启动流程
通过前面几篇的铺垫,现在终于可以进入到tomcat的启动流程了
Tomcat 的启动通常通过执行 catalina.sh start
命令完成。通过如下脚本可知是调用 org.apache.catalina.startup.Bootstrap#main(String[] args)
方法,并传入了 start
参数。
Bootstrap#main
启动流程UML
Bootstrap 初始化
主要是初始化三个类加载器(Common、Catalina、Shared),并实例化Catalina对象,为后续的load和start方法做准备
Catalina#load()
解析 conf/server.xml
配置文件,构建出一个Server树,并初始化Server(Server#init)
Catalina#start()
启动Server组件(Server#start)
重点
容器的init() 并不会向子容器递归传播
除了
Engine
容器在load()
阶段被显式初始化外,其余子容器(如Host
、Context
、Wrapper
)的初始化会延迟到start()
阶段。也就是说,start()
阶段才是触发完整容器结构构建的关键时机Socket 层组件的启动滞后于容器启动
只有整个容器启动完毕,确保业务逻辑准备完毕,然后才启动
Connector
及其内部的ProtocolHandler
和Endpoint
(负责监听端口与处理 Socket 请求)。避免http请求到来时,容器还不可用的状态Context 容器由 HostConfig 解析生成
Host 启动时会触发其绑定的 LifecycleListener — HostConfig,来解析和构造StandardContext子容器
Wrapper、Filter、Listener 由 ContextConfig 解析构建
Context启动中会触其绑定的 LifecycleListener — ContextConfig,来进行全部的web.xml解析,完成对 Wrapper(即 Servlet)、Filter、Listener 等组件的构建与注册
请求流程
流程总结
Acceptor线程(监听并接受连接)
- Acceptor线程监听到8080端口产生的连接,将其构造为PollerEvent提交到Poller 的事件队列中
Poller线程(事件注册和监听)
- 轮询处理事件队列,将
PollerEvent
注册到 Java NIO 的Selector
中,监听OP_READ
事件 - 当某个 channel 上有数据可读时,构造一个
SocketProcessor
实例,并提交给后端的 worker 线程池执行。
- 轮询处理事件队列,将
Worker线程(处理Socket请求)
- SocketProcessor#doRun:进行tcp握手处理
- ConnectionHandler#process:从
Processor
缓存池中获取或新建协议处理器(如Http11Processor
),并交由其处理请求 - AbstractProcessorLight#process:对不同的socket状态进行分发和处理(SocketEvent.OPEN_READ则走到Http11Processor#service)
- Http11Processor#service:通过Http11InputBuffer解析http请求,构造成Request和Response。并分发给CoyoteAdapter#service
- CoyoteAdapter#service:通过Mapper组件将请求 URL 映射到对应的
Host
、Context
、Wrapper
并缓存,再调用顶层容器(Engine
)的Pipeline
,正式进入容器级别的处理逻辑。 - 请求通过容器中内部Pipeline里的Valve,从basic Valve流出再流向下一层容器中的first Valve:StandardEngineValve -> StandardHostValve -> StandardContextValve -> StandardWrapperValve
- 最后一个阀门StandardWrapperValve:先进行Servlet的分配,再构造ApplicationFilterChain(过滤出对当前url能使用的Filter),依次调用
doFilter()
进行链式处理,全部通过后最终便走到Servlet#service中
重点
- Tomcat 使用 责任链(Pipeline + Valve) 模式处理请求流转,清晰解耦了容器级别的处理职责
- Processor 实例在请求结束后可被复用,避免重复构造,提升性能
- NIO + 多线程池模型实现高并发处理,前端是少量 Acceptor/Poller 线程,后端是灵活扩展的 Worker 线程池。