Tomcat总体架构
2021-10-29 17:55:18 1 举报
Tomcat总体架构
作者其他创作
大纲/内容
+init()+start()+stop()+destroy()+addLifeCycleListener()+removeLifeCycleListener()
Wrapper
+start()+stop()
Server
Connector
Pipeline
ProtocolHandler
Container
我们针对所有拥有生命周期的组件抽象了一个接口LifeCycle该接口定义了个组件生命周期管理的核心方法
Engine
Context
LifeCycle
在Tomcat中,Container是一个更加通用的概念。为了与Tomcat中的组件命名一致,我们将Container重新命名为Engine,用以表示整个Servlet引擎。
Service
+addChild()+backgroudProcess()
Host
MapperListener
Catalina
AbstractEndpoint
一个Server可以包含多个Connector和Container,Connector负责开启Socket,用来监听端口请求,返回响应数据;Container负责具体的处理逻辑。Container、Connector都有自己的start()方法和stop()方法,用来开启服务器资源和释放服务器资源。
如何知道我们Conector对应的是哪个Container呢?我们可以维护一个映射表,但是其实并不需要
Tomcat通过类Catalina提供了一个Shell程序,用于解析server.xml创建各个组件,同时,负责启动、停止应用服务器(只需要启动Tomcat顶层组件Server即可)。
我们知道一个Web应用中,可以有多个Servlet实例来处理来自不同链接的请求。因此我们还需要一个组件来表示Servlet的定义。在Tomcat中,我们用Wrapper来表示Servelt的定义。
LifeCycle接口状态图
Executor
如果我们有一台主机,但是有多个域名来的请求服务的时候,我们该怎么做?比如说我们现在有news.number1.com和news.number2.com俩个域名,但是只有一个主机的话,我们应该怎么做,诚然我们可以开启多个服务器实例,但是如果我们在一个服务器实例上应该怎么做呢?我们可以将一个域名当成一个虚拟主机Host来进行处理。
通常情况下,我们通过Socket来监听服务器指定端口来实现该功能。我们通过start()方法来启动服务器,并且通过Socker来监听服务器指定端口,负责监听客户端请求,并作出请求解析和返回响应结果,并且提供了stop()方法来关闭服务器,释放资源。
其次,线程池的共享范围如何确定?在Tomcat中Executor由Service维护,因此同一个Service中的组件可以共享一个线程池。
Mapper
BootStrap
Context表示一个Web应用,一个Engine可以包含多个Context
并发问题
init():初始化组件start():启动组件stop():停止组件destroy():销毁组件
CoyoteAdapter
当然,如果没有定义任何线程池,相关组件(如Endpoint)会自动创建线程池,此时,线程池不再共享。
适配性很差,比如说我们有不同协议请求,但是却有相同的处理结果的时候,我们应该怎么进行处理呢?我们自然能想到的就是将请求处理和网络协议从概念上分离
Processor
Valve
Tomcat容器组件的灵活之处在于,每个层级的容器(Engine、Host、Context、Wrapper)均有对应的基础Valve实现,同时维护了一个Pipeline实例。也就是说,我们可以在任何层级的容器上针对请求处理进行扩展。
我们用Host来表示虚拟主机,一个Host可以有多个Context实例
一个Server可以有多个Service,每个Service可以有多个Connector和Container,这样来自Connection的请求只能有它所属的Service维护的Container来处理请求了。
在增强组件的灵活性和可扩展性方面,职责链模式是一种比较好的选择。Tomcat即采用该模式来实现客户端请求的处理——请求处理也是职责链模式典型的应用场景之一。换句话说,在Tomcat中每个Container组件通过执行一个职责链来完成具体的请求处理。
服务器描述:我们可以将服务器描述为这样:就是当接收到其它计算机发过来的请求之后,我们通过解析进行处理之后,然后再将处理结果作为响应返回给请求的计算机
Tomcat通过适配器模式(Adapter )实现了Connector与Mapper、Container的解耦。Tomcat默认的Connector实现(Coyote)对应的适配器为CoyoteAdapter。也就是说,如果你希望使用Tomcat的链接器方案,但是又想脱离Servlet容器(虽然这种情况几乎不可能出现,但是从架构可扩展性的角度来讲,还是值得讨论一下),此时只需要实现我们自己的Adapter即可。当然,我们还需要按照Container的定义开发我们自己的容器实现(不一定遵从Servlet规范)。
Tomcat定义了Pipeline(管道)和Valve(阀)两个接口。前者用于构造职责链,后者代表职责链上的每个处理器。当然,我们还可以从字面意思来理解这两个接口所扮演的角色——来自客户端的请求就像是流经管道的水一般,经过每个阀进行处理。其设计如图2-11所示。
也许你会有疑问,为什么Tomcat不直接通过Catalina启动,而是又提供了Bootstrap呢?你可以查看一下Tomcat的发布包目录,Bootstrap并不位于Tomcat的依赖库目录下($CATALINA_HOME/lib ),而是直接在SCATALINA_HOME/bin目录下。Bootstrap与Tomcat应用服务器完全松耦合(通过反射调用Catalina实例),它可以直接依赖JRE运行并为Tomcat应用服务器创建共享类加载器,用于构造Catalina实例以及整个Tomcat服务器。
在Tomcat的设计中,Engine既可以包含Host,又可以包含Context,这是由具体的Engine实现确定的,而且Tomcat采用一种通用的概念解决此问题,我们在后续部分会详细讲解。Tomcat提供的默认实现StandardEngine只能包含Host。
经过上面的设计我们已经解决了网络协议和容器的解耦。但是应用服务器是用来部署并运行web应用的,因此我们需要在Engine中支持管理web应用。当接收到Connector的处理请求的时候,都能在Engine中找到一个合适的web来处理请求。
0 条评论
下一页