tomcat的总体设计

tomcat的总体设计 总的来说 就是接受一个请求,然后处理,最后返回。

那么首先要start()服务器,处理完后,stop()服务器

从架构设计上来说,请求模块Connector与处理模块Container应该解耦。这样一个组件的变化不会影响另一个。

Connector负责开启Soket并监听客户端请求,返回响应数据。
Container负责处理具体的请求。
它们拥有自己的start()和stop()方法来加载和释放自己维护的资源。

Connector与Container(Engine)如何关联起来呢?可以通过一个映射规则来解决这个问题,但这不够优雅。优雅的做法是通过Service把Connector和Container(Engine)关联起来,这样多个Connector的请求就能关联到该Service中的Engine处理。

那么,Service是如何优雅的处理的呢?

一个Server可以包含多个Service。一个Service包含多个Connector和一个Container。这样,来自Connector的请求只能有它对应的Container处理。

engine表示整个Servlet引擎,不是servlet容器。引擎负责请求的处理,并不考虑请求连接、协议等的处理。 当engine处理一个请求时,要找到一个合适的web应用(context)来处理。

表示servlet容器的是Server。

因为一个web应用(context)可以包含多个servlet实例来处理不同的请求。这就引出来一个表示servlet实例的组件Wrapper.

容器这个概念指的是一类组件,有时指engine,有时指context,但这类组件的作用就是接收请求,返回结果。
所以我们将一些公共行为抽取到Container。具体操作可以委派到子类去执行。


engine host context wrapper都继承了container容器。
值得注意的是container中有个backgroundProcess()方法。 用于处理一些异步处理。这样子容器只有实现这个方法就可以,不必再单独创建异步线程处理。

每个组件都有init(),start(),stop(),destory()这些流程,那么是不是可以抽取到一个顶层组件呢,答案是肯定的。这样就可以采用一致的流程来初始化、启动、关闭组件

上面的设计可以保证整个架构的伸缩和扩展性。那么,如何让每个组件也可以扩展呢?
答案就是责任链模式。 其实tomcat的每个container就是通过执行一个责任链来完成该容器对请求的处理。
具体的设计就是设计一个管道pipeline和一个value阀接口。请求经过每个value阀进行处理。这样我们可以把一些通用的处理加到任何层级的容器上。

Connector组件。
所谓connector组件必要具备以下功能:监听端口、读取请求、交给容器处理。

endpoint启动线程监听端口,当请求到来时,调用processor读取请求数据.
processor读取到数据后,是怎么知道要哪个容器来处理呢?答案是通过Mapper实现到容器的映射。MapperListenser用于监听容器的变化,当新增容器或者去掉容器时,更新对应的映射信息.


process container mapper通过适配器模式coyoteAdapter关联起来.

观察到上面的架构设计图,是不是觉得少了个什么呢?对,并发。上面都是以串行的方式运行的。并发就离不开线程池。
既然tomcat提供的是一个可插拔的组件环境,那么线程池也是一个组件也进行统一管理,故也实现lifesyle接口。可以在组件中共享这一个线程池。

那么线程池由哪个维护呢?这里是用service来维护的。

从架构图中可以看出,启动只要启动顶层server即可。

现在核心组件都有了,那么如何启动起来呢?看看tomcat的设计启动组件。

Cataline提供一个shell程序解析server.xml创建各个组件,同时负责启动、停止应用服务器。Bootstrap负责创建cataline实例,调用cataline相关方法完成启动,停止。Bootstrap与Cataline不在一个包中的设计,值得学习。

我们看下容器的类继承图


Container作为顶层接口,Engine、Host、Context、Wrapper都继承该接口。然后每个接口有自己的实现类。同时继承同一基础类。
为什么要设计个顶层接口?
统一抽象为一个概念Container。有利于加入子容器。

`public void addChild(Container child);`  
复制代码

要为一个组件加入别的组件怎么设计呢?对,用setter和getter来加入别的组件。

    public void setLoader(Loader loader);
    public void setCluster(Cluster cluster);
    public void setCluster(Cluster cluster);
    .....
复制代码

Container怎么与管道关联起来呢?
在ContainerBase中定义一个成员变量:

 protected Pipeline pipeline = new StandardPipeline(this);
复制代码

这样容器就和管道关联起来了。

转载于:https://juejin.im/post/5b3dc9c5f265da0f970d0c93

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值