Tomcat架构简述

文章目录

  • Tomcat体系结构
  • 架构模块说明
    • Server
    • Connector和Container
    • Host、Context和Wrapper
      • 为什么这么设计?
    • Valve
    • Lifecycle

Tomcat体系结构

我们可以从 server.xml 中就能够看出 Tomcat 各组件的层次结构,具体结构图如下:
Tomcat架构简述_第1张图片

  • Server:代表整个容器,接收客户端发来的请求数据并进行解析,完成相关业务处理,然后把处理结果作为响应返回给客户端。它可能包含一个或多个 Service 和全局 JNDI 资源;
  • Service:包含一个或多个 Connector,这些连接器与一个 Engine 相关联;
  • Engine:表示这个Servlet引擎,而非Servlet容器。表示Servlet容器的是Server。Engine用于处理流水线(pipeline),它接收所有连接器的请求,并将响应交给适当的连接器返回给客户端;
  • Host:网络名称(域名)与 Tomcat 服务器的关联,默认主机名 localhost,一个 Engine 可包含多个 Host;
  • Connector:负责开启Socket并监听客户端请求、返回响应数据。处理与客户端的通信,网络 I/O;
  • Container:负责具体的请求处理。
  • Context:表示一个 Web 应用程序,一个 Host 包含多个上下文。

架构模块说明

Server

从某种意义来说,Server也算是一种应用,那种应用呢?
​它可以接收其他计算机,也即是客户端发来的请求,它处理请求,然后将处理后的结果返回给请求的客户端。通常情况下,我们通过使用Socket监听服务器指定端口来实现该功能。
按照最简单的仅仅是用作嵌入在应用系统中的一个远程请求处理方案,而且我们的系统访问量很低,那么我们可以设想下,Server只需要两个操作就是可以了:start()和stop()。一个是启动服务,一个关闭服务。如下图
Tomcat架构简述_第2张图片
但我们需要的是一个应用服务器的话,就不能这么简单了。

Connector和Container

Connector: 负责请求的接收和响应
Container: 负责具体的请求处理
我们知道,应用服务器只有Server启动和关闭是不行的。需要提供应用服务的功能,就要有接收需求、处理需求、响应需求的功能如下图。为什么要将请求响应和处理分开不同的处理模块。主要原因如下:

  1. 单一职责原则;
  2. 请求协议(HTTP/HTTPS/AJP等)有多种,而处理逻辑比较统一;
    Tomcat架构简述_第3张图片
    如上图,但这样也有问题,即Server中包含多个Connector和Container,那么来个请求后,Connector怎么知道这个请求交给哪个Container来处理呢?我们也可以在中间建立个映射来解决,但不是最优的,因为后来会多出很多组件,这样映射关系会越来越复杂。
    那么我们就引入一个Service组件,而这个组件,进行包装和维护多个Connector和Container。而来自Connector的请求只能由它所属Service维护的Container处理。结构图如下:
    Tomcat架构简述_第4张图片

Host、Context和Wrapper

现在我们的应用服务可以启动,可以接受请求并处理请求。而且,多个请求方式,对应一个处理。那么这个可以想到多个域名服务了。
如下两个URL:
http://www.beijing.com/app/index.html
https://www.beijing.com/staple/list.html
这个应用均有一个主机处理,怎么实现呢?
我们可以先看看Tomcat是如何进行配置和模块定制化的,如下图:
Tomcat架构简述_第5张图片
StandEngine, StandHost, StandContext及StandWrapper是容器,他们之间有互相的包含关系

为什么这么设计?

Tomcat架构简述_第6张图片

  • Wrapper封装了具体的访问资源,例如 index.html;
  • Context 封装了各个wrapper资源的应用名称,例如 app;
  • Host 封装了各个context资源的集合;
    按照领域模型,这个典型的URL访问,可以解析出三层领域对象,他们之间互有隶属关系。层层递进,层层组合。那么host的集合就是Engine。每个模块各司其职,通过配置(server.xml)就可以很大限度的扩展Tomcat。设计的很灵活。
    如果说以上三个容器是物理模型的封装,那么Engine可以作为一种逻辑的封装。 到此结构关系如下图:
    Tomcat架构简述_第7张图片

Valve

从Tomcat的结构图可以看出,是按照层次,分别封装成一个对象。
为什么要这样做呢
这主要是为了方便统一管理。类似命名空间的概念,在不同层次的配置,其作用域不一样。以tomcat自带的打印request与response消息的RequestDumperValve为例。这个valve的类路径是:

org.apache.catalina.valves.RequestDumperValve

valve机制是Tomcat非常重要的处理逻辑的机制。
如果这个valve配置在server.xml的Context节点下,则其只打印出访问这个应用的的request与response消息。
如果这个valve配置在server.xml的Host节点下,则其可以打印出访问这个Host下所有应用的request与response消息。

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
	<Valve className="org.apache.catalina.valves.RequestDumperValve"/>
	<Context path="/beijing" docBase="/usr/local/tomcat8/web/mingjing" >Context>
	<Context path="/shanghai" docBase="/usr/local/tomcat8/web/mingjing" >Context>
Host>

Lifecycle

在进一步深入细化应用服务器设计之前,我们希望从抽象和复用层面审视一下当前的设计,我们可以看出,所有的组件均有start()和stop()等生命周期方法,拥有生命周期管理的特性。所以就有了进一步的针对生命周期管理的接口抽象——Lifecycle。结构修改如下图:
Tomcat架构简述_第8张图片

Tomcat中的组件都交给这个接口管理,但是具体组件的生命周期是由包含组件的父容器来管理的,Tomcat中顶级容器管理着Service的生命周期,Service容器又是Connector和Container的父容器,所以这两个组件的生命周期是由Service管理的,Container也有子容器,所以管理着这些子容器的生命周期。这样,只要所有组件都实现了Lifecycle接口,从顶层容器Server开始,就可以控制所有容器的生命周期了。而这里使用了观察者模式,包括Pipeline和Valve的责任链模式,有一篇Tomcat涉及的设计模式中有详细讲解。

你可能感兴趣的:(Tomcat)