Tomcat源码架构笔记(servlet请求处理链路篇)
在上一篇文章中,我们在debug模式下完整的跟踪程序走了一遍,对Tomcat start启动阶段所做的操作有了大概的了解。
这回,我们一起看看,Tomcat服务器接受到一个请求到处理这个请求之间经历了怎样的过程。

Servlet请求处理链路分析
- 一个servlet如何被tomcat处理的?
- servlet请求 -> 可以处理当前servlet请求的servlet实例 -> servlet.service()
Servlet请求处理链路和URL的对应关系在上一篇文章中我们知道Acceptor线程主要负责监听Socket嵌套字请求,并将其转给sekector(选择器)。
而poller线程,则负责检查sekector(选择器)中是否有数据到来的channel,如果有就进行处理。
NIO模型所以Servlet请求处理链路中最重要的就是poller线程,他负责控制这一系列的操作。
Servlet请求处理链路流程
Poller线程启动Poller线程和Acceptor线程
NioEndpoint.startInternal()我们可以看到在启动Acceptor线程,监听Socket之前,startInternal()方法先启动了Poller线程。
Poller类的核心方法就是run()方法。
他来负责循环检查selector中是否有事件就绪,并在数据可用的时候转给Worker线程。
NioEndpoint类 Poller.run() ①
NioEndpoint类 Poller.run() ②处理Channel(可以理解为处理Socket)
NioEndpoint类 Poller.processKey()处理Socket请求具体方法
当Socket传进processSocket()方法中,先判断该Socket是否为空。
不为空,则开始在线程池中检查获取SocketProcessor处理线程(如果线程池中没有,就创建一个)。
AbstractEndpoint.processSocket() ①使用线程池技术执行SocketProcessor处理线程。
AbstractEndpoint.processSocket() ②其中核心处理方法就是该线程的run()方法。
SocketProcessorBase.run()子类中doRun()方法的逻辑,首先取出对象,并判断握手状态。
NioEndpoint类 SocketProcessor.doRun()确定握手完成后,调用process()方法进一步处理。
NioEndpoint类 SocketProcessor.doRun()process方法(Handler处理请求)
AbstractProtocol.process()获取一个Processor(应用层协议)。
AbstractProtocol.process()调用该Processor(应用层协议)处理请求。
AbstractProtocol.process()HttpProcessor进行内容请求解析
AbstractProcessorLight.process()READ读状态处理(分支处理)
AbstractProcessorLight.process()应用层处理器HttpProcessor对请求进行解析处理
Http11Processor.service()解析封装原生Request/Response完成之后,要传入Adapter适配(由Adapter继续处理Request/Response)
Http11Processor.service()CoyoteAdapter需要将Request/Response进一步封装为HttpServletRequest/HttpServletResponse
CoyoteAdapter.service()根据URL找到可以处理该请求的对应组件(Mapper机制,详见下一节)
CoyoteAdapter.service()
CoyoteAdapter.postParseRequest()开始匹配
Mapper.map()真正的匹配逻辑
Mapper.internalMap()request.getHost()就是从刚才封装好的mapperData中取出Host
StandardEngineValve.invoke()
mapperData
AbstractAccessLogValve.invoke()
ErrorReportValve.invoke()Host中要去进一步把处理当前请求的Context取出来
StandardHostValve.invoke()把请求传递给context处理
StandardHostValve.invoke()
AuthenticatorBase.invoke()寻找可以处理当前请求的wrapper
StandardContextValve.invoke()调用wrapper容器处理请求
StandardContextValve.invoke()寻找可以处理当前请求的Servlet
StandardWrapperValve.invoke()把能够处理当前请求的servlet示例从wrapper容器中取出来
StandardWrapperValve.invoke()为当前请求的处理生成一个过滤器链(在这个链路的核心逻辑要触发servlet调用)
StandardWrapperValve.invoke()执行过滤器链
StandardWrapperValve.invoke()过滤器链执行的核心方法
ApplicationFilterChain.doFilter()
ApplicationFilterChain.internalDoFilter()
控制台打印执行结果Mapper组件体系结构
Mapper组件体系结构Tomcat中使用了Mapper机制重新封装了Host -> Context -> Wrapper(Servlet) 之间的数据和关系。
MapElement在匹配出能够处理当前请求的Host -> Context -> Wrapper(Servlet) ,Mapper对象通过MapperListener.start();来完成初始化好了。
StandardService.startInternal()StandardService -> StartInternal() -> MapperLintener.start()中完成Mapper对象初始化。
注册Host
MapperLintener.start()循环添加Host
MapperLintener.registerHost()此时,Mapper对象已经初始化完毕了
Host
Context
Wrapper(Servlet)OK,至此Tomcat基本的初始化、启动、处理请求的过程已经梳理一遍了。
Tomcat通过套娃的设计,带来了层级分明的结构;
Tomcat通过统一的生命周期管理接口,让各个组件有序工作;
Tomcat通过使用多线程带来了效率与性能的提升;
正确的debug方式,可以轻松深入代码解决问题;
