Tomcat学习1:架构设计
Tomcat是什么
Tomcat是一个servlet容器,同时也具备HTTP服务器的功能,我们称其为web容器;servlet容器和实现业务的servlet接口的一整套规范就是servlet规范,其扩展性包含了干预过程的Filter和基于状态的Listener;
作为一个HTTP服务器,主要是接受连接,解析请求数据,处理请求和发送响应结果;
servlet容器用来加载管理具体的业务类,实例化和调用具体的servlet。
1):一次请求经过http服务器和servlet的流程?
2):Filter和Listener的具体应用场景?
3):Servlet容器和Spring容器的关系?
4):如何实现一个HttpServlet类?
Tomcat架构为什么这么设计
tomcat设计的核心是为了解决两个问题:建立连接&处理请求,对应了两个核心组件Connector和Container。
客户端发送一个HTTP请求的完整过程:
针对这个HTTP请求,Tomcat用start方法封装前五个步骤,启动并处理请求,stop方法封装第6步,关闭连接,停止服务。可以抽象出如下结构:
这样请求的监听和请求处理放一起扩展性很差,按照职责分离出Connector和Container
多个Connector和Container,如何知道Connector的请求由哪个Container处理?通过维护一个复杂的映射表来解决。这个映射表该怎么维护?抽象出一个service
一个service负责维护多个Connector和一个Container,每个请求都找到唯一的Container进行处理。(也即是Engine,标识整个servlet引擎,引擎只负责处理请求)
1:Container容器设计
网络连接和处理请求解耦了,但是应用服务器是用来部署并运行web应用的,引擎不怎么变化,而业务逻辑是经常变化的,不可能把所有的业务逻辑写到Engine中。
1):如何解决引擎和业务逻辑耦合问题? 用一个Context表示一个web应用(一个Engine包含多个Context),Context拥有自己的start和stop。
将加载和释放资源分解到每个组件中,组件之间解耦,提高服务器可维护性和可扩展性
2):一个应用服务器如何来承担多个多个域名的服务呢?
通过增加Host节点,把每一个域名抽象出也给虚拟主机,每个虚拟主机下包含多个web应用。Tomcat的Engine即可包含Host解决多个域名映射的问题,也可以直接包含Context表示一个应用。
3):在Servlet规范中,一个Web应用可以包含多个servlet实例来处理相同域名下的不同路径的请求。因此,定义了Wrapper组件来标识Servlet定义
4):上面一直提到的容器,有时指Enginer有时指Context,它代表了一类组件,这类组件的作用就是处理请求并返回数据。尽管具体的操作会委派到各子组件完成,但是他们的行为定义是一致的。
基于此,我们使用Container表示容器,可以添加并维护子容器,所以Enginer,Host,Context,Wrapper均继承自Container
Tomcat容器还有一个后台处理的功能,执行一些异步任务,比如定期扫描web应用文件变更。tomcat对此定义了backgroudProcess方法。
5):每个组件都存在启动停止等生命周期方法,基于此抽象出一个生命周期管理的通用接口Lifecycle,定义生命周期管理的核心方法
init()
start()
stop()
destory()
同时,该接口支持组件状态之间的转换,支持添加事件监听器用于建通组件的状态变化,我们可以采用一致的机制来初始化、启动停止、销毁各组件。
Tomcat核心组件默认实现均继承自LifecycleBeanBase抽象类。
6):以上应用服务器的整体架构的可扩展性和可伸缩性的设计,除此,希望每个组件都应该是可扩展的。
对此每个container组件采用了责任链模式来处理请求,即管道Pipeline和阈Value两个接口,前者负责构造责任链,后者代表链上的每个处理器。Pipeline中有getBasic方法,负责调用下一层容器的第一个Value。
至此,Container的整体设计大致完成。
2:Connector连接器设计
要与Container完成一次完整的请求,Connector至少包含以下功能:
1:监听服务器端口,接收来自客户端请求 -- Endpoint(BIO,NIO等)
2:对请求中的数据流按照指定的协议进行解析 -- Processor(HTTP,AJP等)
3:根据请求地址映射到指定的容器处理
ProtocolHandler标识一个协议处理器,针对不同的协议和I/O方式具体不同的实现组合,如Http11NioProtocl表示基于NIO的HTTP协议处理器。
Tomcat通过Mapper和MapperListener两个类实现请求映射功能。前者维护容器映射关系,按照规则查找容器;后者实现了ContainerListener和LifecycleListener。
Tocmat通过适配器模式实现了Connector、Mapper、Container的解耦,Connector默认实现了适配器Adapt
但是在高并发场景下,Tomcat如何支持?通过线程池。
Tomcat中Executor由Service维护,同一个Service中的组件可以共享一个线程池。如果Service没有创建,EndPoint组件会自动创建线程池(不共享)。
EndPoint监听socket端口,接收到请求后,创建一个请求对象,交由线程池处理。
整个框架的设计思路都是可插拔的组件化设计思想,那接入线程池也作为一个组件统一管理
以上,Tomcat各组件设计大致如此