Tomcat 架构的认知
一. 概述
下面是有关 tomcat 的架构图,这里不过里面的细节进行解读;只关注一个请求是怎么流转到 Servlet 进行大概的梳理;同时,我们是基于 spring-boot 框架中包含的 tomcat 源码进行解读;
二. 时序图
一个 Web 服务器,首先需要有一个监听线程。当请求过来,该线程就会接收到一个 socket 对象,然后交由 Processor 接口对应的实现类去解析,将解析后的请求数据,扔给 CoyoteAdapter 对象接着。如下图;这里没有忽略了很多细节,如 IO 多路复用的逻辑等;
上图还没涉及到 Service、Engine、Host、Context、Wrapper 相关的类;只是简单的画到 CoyoteAdapter 对象,其实际后面还有很长的链路;为了更加可观,我将其拆分出来;
通过上面的三张时序图,我们大体清楚地一个请求是如何流转到 Servlet 实现类的;
三. 关键问题解读
tomcat 包含的细节过多,如果去梳理里面的细节,会陷入死循环。所以我们带着问题去解读关键的代码逻辑;
1. 请求 URL 映射 Servlet
当一个请求过来的,我们会解析该 URL,找到对应的 Servlet 对象,然后封装到 StandardWrapper 中保存到 Request 对象中;接着通过 PipeLine 执行,最终到 StandardWrapperValve 时,获取 Request 中的 Wrapper 对象。接着就运行如上第三张时序图的流程;
具体映射的逻辑在 CoyoteAdapter 类;其通过 Service 对象的 Mapper 对象去映射逻辑,具体是调用如下方法:
2. session 管理
会话对象默认的实现类是 StandardSession,其会话管理接口是 Manager,默认的实现类为 StandardManager,该类是基于内存式管理会话对象;
那么问题来了,如何实现会话共享呢?
其实质是需要我们实现该 Manager 接口,然后注入到 tomcat 容器里面;至于如何注入?
一种形式是通过 context.xml,去修改,该方式算是过时的;
在 spring boot 中,提供这样子的接口 TomcatContextCustomizer,可以让我们去自定义这个上下文 Context,代码处:
3. 添加 Servlet/Filter
在 tomcat 中提供这样子的注解 @WebServlet,@WebFilter;然后并没有提供扫描 classpath 下的含有该注解的类向 Context 注入 Servlet;而在 spring-boot 框架中提供了这么一个类 ServletComponentScanRegistrar 可以扫描指定路径下的含有这些注解的对象向容器中注入,我们可以使用 @ServletComponentScan 去指定路径;
4. ServletContainerInitializer
tomcat 中提供了这个 ServletContainerInitializer 接口,可以对 Context 进行配置;在 spring-boot 框架中提供了主要的实现类为 TomcatStarter 类,然而 TomcatStarter 类中包含了 ServletContextInitializer 集合列表,可以对 ServletContext 进行初始化;有关 ServletContextInitializer 实现类有如下:
SessionConfiguringInitializer 对 Session 进行配置初始化
ServletListenerRegistrationBean 向 Servlet 容器中注册监听器;
ServletRegistrationBean 向 Servlet 容器中注册 Servlet
FilterRegistrationBean 向 Servlet 容器中注册 Filter
四. 总结
这里对 tomcat 的原理细节没有过多讲解,通过上面的几个点梳理,当在开发过程中需要基于 tomcat 下进行拓展的场景下,可以快速找到对应的代码处;后面会逐步完善该文章,另外值得推荐的是一本书:《Tomcat 内核设计剖析》,作者汪建
版权声明: 本文为 InfoQ 作者【邱学喆】的原创文章。
原文链接:【http://xie.infoq.cn/article/070b124cd0c8edf3758ac40ad】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论 (2 条评论)