前言
参考书籍《Tomcat架构解析》。
书中主要以启发式讲解tomcat架构为主,讲的很详细,本文主要是梳理逻辑。
正文
从最基本的功能来讲,我们可以将服务器描述为这样一个应用:
它接收其他计算机(客户端)发来的请求数据并进行解析,完成相关业务处理,然后把处理结果作为响应返回给请求计算机(客户端)。
基本架构
1.Server
定义:
表示整个Servlet容器,整个Tomcat运行示例中仅有唯一一个Server实例。
2.Service:
定义:
Service表示一个或多个Connector的集合。
一个Server可以包含多个Service,每个Service用于维护其中多个Connector与一个Container,即来自多个Connector的请求只能由此Service所维护的Container处理。不同Service之间相互独立,仅共享一个JVM以及系统类库。
3.Container
定义:
Container表示能够执行客户端请求并返回响应的一类对象。
在Tomcat中存在不同级别的Container容器:Engine、Host、Context、Wrapper。
是整个Tomcat的处理逻辑核心。
结构图:
此外,Tomcat的Container还有 一个很重要的功能,就是后台处理。在很多情况下,我们的
Container需要执行一些异步处理,而且是定期执行,如每隔30秒执行一次,Tomcat对于Web应用文件变更的扫描就是通过该机制实现的。
Tomcat针对后台处理,在Container上定义了backgroundProcess()方法,并且其基础抽象类( ContainerBase )确保在启动组件的同时,异步启动后台处理。因此,在绝大多数情况下,各个容器组件仅需要实现Container的background-Process()方法即可,不必考虑创建异步线程。
4.Connector:
定义:
负责监听并处理Socket请求,根据不同的协议与I/O方法选择不同的实现逻辑并交给对应的Container处理。
主要作用:
监听服务器端口,读取来自客户端的请求。
将请求数据按照指定协议进行解析。
根据请求地址匹配正确的容器进行处理。
将响应返回客户端。
支持协议:
HTTP(默认)
AJP(默认)
HTTP/2(Tomcat8之后)
I/O协议:
BIO(Tomcat8.5之后移除)
NIO
APR
NIO2(Tomcat8之后)
结构图:
ProtocolHandler:
协议处理器,针对不同的协议类型与I/O方法提供不同实现。
其中,Endpoint用于启动Socket监听,并调用对应的Processor处理;
Processor:
为具体的处理逻辑实现。
5.Mapper和MapperListener
定义:
Mapper用于维护容器映射信息,同时按照映射规则(Servlet规范定义)查找容器。
MapperListener实现了ContainerListener和LifecycleListener, 用于在容器组件状态发生变更时,注册或者取消对应的容器映射信息。
为了实现上述功能,MapperListener实现了Lifecycle接口,当其启动时(在Service启动时启动),会自动作为监听器注 册到各个容器组件上,同时将已创建的容器注册到Mapper。
设计逻辑:
当Processor读取客户端请求后,需要按照请求地址映射到具体的容器进行处理,这个过程即为请求映射。由于Tomcat各个组件采用通用的生命周期管理,而且可以通过管理工具进行状态变更,因此请求映射除考虑映射规则的实现外,还要考虑容器组件的注册与销毁。
6.Adapter:
定义:
默认为Coyote的servlet Container入口点。
设计逻辑:
Tomcat通过该适配器模式实现Connector与Mapper、Container的解耦。
若想要使用Adapter方案,但是又想脱离Servlet容器,只需实现自定义的Adapter即可,但同样的,自定义的容器实现需满足Container定义。
7.Engine:
定义:
Engine表示整个Servlet引擎。在Tomcat中,Engine为最高层级的容器对象。尽管Engine不是直接处理请求的容器,却是获取目标容器的入口。
8.Host:
定义:
Host作为一类容器,表示Servlet引擎(即Engine)中的虚拟机,与一个服务器的网络名有关,如域名等。客户端可以使用这个网络名连接服务器,这个名称必须要在DNS服务器上注册。
9.Context:
定义:
Context作为一类容器,用于表示ServletContext,在Servlet规范中,一个ServletContext即表示 Context。
10.Wrapper:
定义:
Wrapper作为一类容器,用于表示Web应用中定义的Servlet Executor。
11.Executer:
定义:
表示Tomcat组件间可以共享的线程池。
在Tomcat中Executor由Service维护,因此同一个Service中的组件可以共享一个线程池。如果没有定义任何线程池,相关组件( 如Endpoint)会自动创建线程池,此时,线程池不再共享。
在Tomcat中,Endpoint会启动一组线程来监听Socket端口,当接收到客户端请求后,会创建请求处理对象,并交由线程池处理,由此支持并发处理客户端请求。
12.Lifecycle:
定义:
用于管理组件生命周期的核心接口,提供通用性定义用于应用服务器的统一管理。
设计逻辑:
Tomcat中所有组件均存在启动、停止等生命周期方法,拥有生命周期管理的特性。因此,Tomcat针对所有拥有生命周期管理特性的组件抽象了一个Lifecycle通用接口,该接口定义了生命周期管理的核心方法。
Init(): 初始化组件
start(): 启动组件
stop(): 停止组件
destory(): 销毁组件
addLifecycleListener(): 添加LifecycleListener以用于监听组件状态。
removeLifecycleListener(): 移除LifecycleListener。
Tomcat核心组件的默认实现均继承自LifecycleMBeanBase抽象类,该类不但负责组件各个
状态的转换和事件处理,还将组件自身注册为MBean,以便通过Tomcat的管理工具进行动态维护。
Lifecycle状态转换:
状态图:
Tomcat生命周期事件与状态映射:
Tomcat默认提供了3个与状态无关的事件类型,其中PERIODIC_ EVENT主要用于Container的后台定时处理,每次调用后触发该事件。
CONFIGURE_START_ EVENT和CONFIGURE_ STOP_ EVENT将在一些组件的configure加载中起到作用。
处理逻辑
将上述组件整理一下,整个Tomcat的组成可概括为:
从这个角度来看Tomcat可分为两部分,Connector与Container。
Connector又分为ProtocolHandler与Adapter。
ProtocolHandler主要用于处理底层的Socket链接(其实是一个SocketChannel对象),然后通过Processor处理为Tomcat Request交给Adapter。
Adapter作为Connector与Container的连接器,自然需要将我们的Request请求转发给Container,但为了满足servlet规范,Adapter将会在这里将其转换为标准的ServletRequest。
在通过Mapper查找到映射关系后,Adapeter将会使用getPipeline()获取Pipeline中的Basic Value 将request传入Containner中。
上述文章只是一个简略描述,实际的处理逻辑会更加复杂。
传入Container后的处理逻辑在这里不过多描述,我们常用的Servlet,Filter,Listener内存马都是在Container中实现,关于它们的原理网上也已有很多分析。
补一张各组件的请求流程处理图:
后记
学习笔记一篇。