Tomcat架构解析之Container设计

一、前言

为了使大家能够更加深刻的理解Tomcat的相关组件的概念,将采用一种启发式的讲解方式来介绍Tomcat的总体设计。从如何设计也应用服务器开始,逐步完善,直至最终导出Tomcat的整体架构。

二、Server

    从最基本的功能来讲,我们可以将服务器描述我这样一个应用:
        它接收客户端发来的请求数据并且进行解析,完成相关业务处理,然后把处理结果作为响应返回给客户端。

    通常情况下,我们通过使用Socket监听服务器指定端口来实现该功能。按照该描述,一个最简单的服务器设计如下图所示:
在这里插入图片描述
    我们通过start()方法启动服务器,打开Socket链接,监听服务器端口,并且负责在接收到客户端请求时候进行处理并且返回响应。提示提供一个stop()方法来停止服务器并且释放网络资源。

    如果我们设计的不是一款启动服务器,仅仅是作为嵌入在应用系统中的一个远程请求处理方案,并且我们的应用系统访问量很低,那么这个也许是可行的方案。

三、Connector和Container

    其实,将请求监听与请求处理放在一起扩展性很差,比如当我们想适配多种网络协议,但是请求处理却相同的时候。要知道自从Tomcat诞生起,他就始终支持与Apache集成,无论是通过AJP协议还是HTTP协议。当Web应用通过Tomcat独立部署的时候,我们选择使用HTTP协议为客户端提供服务;当通过Apache进行集群部署的时候,我们使用AJP协议与Web服务器进行链接。应用服务器(Tomcat)在两种部署架构下切换时,确保Web应用不需要做任何变更。

    那么如何通过面向对象的方式来解决这个问题?自然的想法就是将网络协议与请求处理从概念上分离。

如下图所示:
在这里插入图片描述
    一个Server可以包含多个Connector和Container。其中Connector负责开启Socket并且监听客户端请求、返回响应数据;Container负责具体的请求处理。Connector和Container分别拥有自己的start()和stop()方法来加载和释放自己维护的资源。

    但是,这个设计有个明显的缺陷。既然Server可以包含多个Connector和Container,那么如何知道来自某个Connector的请求是由哪个Container处理呢?当然,我们可以维护有个复杂的映射规则来解决这个问题,但是这并不是必须的。
在这里插入图片描述
    一个Server包含多个Service,他们互相独立,只是共享一个JVM以及系统类库,一个Service负责维护多个Connector和一个Container,这样来自Connector的请求只能由他所属的Service维护的Container处理。

    在Tomcat中,Container是一个更加通用的概念。为了与Tomcat中的组件命名一直,将Container重新命名为Engine,用以表示整个Servlet引擎。

修改后的设计图如下所示:
在这里插入图片描述

四、Container设计

    上面的设计已经解决了网络协议的容器的解耦,但是应用服务器是用来部署并且运行Web应用的,是一个运行环境,而不是一个独立的业务处理系统。因此,我们需要在Engine容器中支持管理Web应用,当接收到Connector的处理请求时,Engine容器能够找到一个合适的Web应用来处理。

在上面一副图的设计方案的基础上,一种比较朴素的实现方案如下图所示:
在这里插入图片描述
注意:使用Context来表示一个Web应用,并且一个Engine可以包含多个Context。

    这是不是一个合理的方案呢?
    假设我们有一台主机,他承担了多个域名的服务,我们如何实现呢?当然,我们可以再该主机上运行多个服务器实例,当时如果我们希望运行一个服务器实例呢?因为,作为应用服务器,我们应该提供尽量灵活的部署方式。

    既然我们要提供多个域名的服务,那么就可以将每个域名视为一个虚拟的主机,在每个虚拟主机下包含多个Web应用。因为对于客户端用户来说,他们并不了解服务端使用几台主机来为他们提供服务,只知道每个域名提供了哪些服务,因此,应用服务器将每个域名抽象为一个虚拟主机从概念上是合理的。

根据这个想法修改后的设计图 如下所示:
在这里插入图片描述
注意:用Host来表示虚拟主机的概念。一个Host可以包含多个Context。

    如果阅读Servlet规范,就会知道,在一个Web应用中,可以包含多个Servlet实例以处理来自不同链接的请求。因此,我们还需要一个组件概念来表示Servlet定义。在Tomcat中,Servler定义被称为Wrapper。

基于此修改后的设计图如下所示:
在这里插入图片描述
    使用Container来表示容器,Container可以添加并且维护子容器,因此Engine、Host、Context、Wrapper均继承自Container。将他们之间的组合关系改为虚线,以表示他们之间是有弱依赖的关系,即他们之间的关系是通过Container的父子容器的概念体现的。不过Service持有的是Engine接口。

基于这个概念,再次修正了设计,如下图所示:
在这里插入图片描述
    此外,Tomcat的Container还有一个很重要的功能,就是后台处理。在很多情况下,我们的Container需要执行一些异步处理,而且是定期执行,如每隔30秒执行一次,Tomcat对于Web应用文件变更的扫描就是通过该机制实现的。Tomcat针对后台处理,在Container上定义了backgroundProcess()方法,并且其基础抽象类(ContainerBase)确保在启动组件的同时,异步启动后台处理。因此,在绝大多数情况下,各个容器组件仅需要实现Container的backgroundProcess()方法即可,不必考虑创建异步线程。

附:Tomcat的目录结构以及主要文件。
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值