Tomcat 容器是对 Servlet 规范的实现,也称为 Servlet 引擎。在分析 Tomcat 容器的设计和实现之前,首先简单了解一下 Servlet 规范,弄清楚 Tomcat 究竟要实现什么?

1. Servlet 规范简述

Servlet 是什么?javadoc 中已经明确说明:

Servlet 是在 Web 服务器中运行的 Java 程序,通常用于接收并响应来自 Web 客户端的 HTTP 请求。

Servlet 提供了更高级的抽象,让研发专注于如何处理请求和响应,而不必关心底层网络的处理。像连接处理、解析 HTTP 等都由容器实现,那又是谁决定了容器应该做什么?

答案是 Servlet 规范,简单来说它主要指导解决以下问题:

  • 容器如何管理 Servlet 的生命周期
  • 容器怎么表示请求和响应,怎么映射请求到 Servlet,怎么执行 Servlet
  • 一个 Web 应用的目录组织方式以及容器如何部署一个 Web 应用
  • 其他组件的行为,如过滤器-Filter,监听器-Listener,会话-Session
  • 容器安全性问题,如授权、认证以及类隔离

javax.servlet 包中的类和接口,描述并定义了 Servlet 类与容器提供的运行时环境之间的契约。容器和应用对相关类和接口的实现情况如下:

容器实现的类或接口的作用如下:

  • ServletContext: 表示一个 Web 应用程序,是 Servlet 运行的上下文,定义了一组与容器通信的方法
  • ServletRequest: 封装客户端请求,容器会创建一个它的实例,并传给 serlvet 的 service 方法
  • ServletResponse: 封装服务端响应,容器会创建一个它的实例,并传给 serlvet 的 service 方法
  • FilterChain: 过滤器调用链视图,控制过滤器的调用
  • RequestDispatcher: 转发请求,将请求转发给 JSP 或另一个 Servlet
  • HttpSession: 用户会话,一个与 cookie 关联

2. Tomcat 引擎设计

Tomcat 在内部抽象出了容器和组件的概念,基本结构如下:

容器可以执行接收的请求,并返回响应。容器之间是一种一对多的包含关系,在运行时,它们通过内部的 pipeline(管道) 串联起来。容器主要有以下几种:

  • Engine - 顶级容器,不能被其他容器包含,它接受处理连接器的所有请求,并将响应返回相应的连接器,子容器通常是 Host 或 Context
  • Host - 类似 Apache 虚拟主机的概念,包含主机名称和IP地址,这里默认是localhost,父容器是 Engine,子容器是 Context
  • Context - 表示一个 Web 应用程序,是 Servlet、Filter 的父容器
  • Wrapper - 表示一个 Servlet,它负责管理 Servlet 的生命周期,并提供了方便的机制使用拦截器,没有子容器

容器可以和多个组件关联,组件主要提供通用或定制的功能:

  • Loader - 类加载器,用于在运行时加载类到容器
  • Manager - 管理 Session 池
  • Realm - 安全域的只读接口,用于验证用户身份及其相应角色
  • Vavle - 与特定容器关联的请求处理组件,由容器的 Pipeline 管理,取义于阀门在现实世界的管道中用来控制或修改流量
  • Listener - 这里只是一个统称,主要想强调容器内部设计了很多事件,比如组件的生命周期事件,容器属性变动的事件等

Servlet 引擎就是由容器和组件组合嵌套而成,实现时设计的类图及类的核心方法如下(Tomcat 版本 6.0.53):

3. 容器生命周期的设计

容器的大部分实现依赖于 Lifecycle(如启动、配置),Lifecycle 是观察者模式的应用,Tomcat 使用 LifecycleSupport 类用于周期事件的添加、删除和触发。运用 Lifecycle 在实现时大量使用接口而不是具体的类,更加灵活。

Tomcat 设计了 init、start、stop、destroy和periodic 五类事件,其中 periodic 是一个定时触发事件,由每个容器所属的后台线程触发。容器在初始化时会默认添加一个用于配置的 Listener,如上图所示,类的作用如下:

  • EngineConfig: 无具体功能
  • HostConfig: 主要负责创建 Context 实例;检查已部署应用资源是否变化并重新部署
  • ContextConfig: 主要负责解析 web.xml 初始化 Servlet、Filter、Listener,添加资源监控目录,供 Loader 热加载

4. Pipeline 管道的设计 - 执行 Servlet

Pipeline 是一个很常用的处理模型,和 FilterChain 大同小异,都是责任链模式的实现,Pipeline 内部有多个 Valve,这些 Valve 因栈的特性都有机会处理请求和响应。

Tomcat 的实现类是 StandardPipeline,内部的 Valve 是一个有固定尾节点的单链表,插入时采用头插法逆序插入,读取时使用头结点顺序读取。

这里主要对每个容器的固定 valve 的功能进行分析,容器也是通过最后一个 valve 串联起来:

  • StandardEngineValve: 根据请求的服务器名称,选择适当的 Host 来处理此请求
  • StandardHostValve: 主要功能如下:
    • 匹配 Context,绑定当前 Web 应用的类加载器到当前线程,进入 Context 管道处理请求
    • 响应返回时,如果有异常,生成错误页面,并还原线程的类加载器
  • StandardContextValve: 主要功能如下:
    • 禁止直接访问 WEB-INF 和 META-INF目录
    • 若进行了热加载,重新关联类加载器
    • 获取匹配的 Wrapper 和配置的 ServletRequestListener,进入 Wrapper 管道处理请求
    • 响应返回时,销毁之前初始化的 ServletRequestListener
  • StandardWrapperValve: 主要功能如下:
    • 反射加载一个 Servlet 实例,并创建一个过滤器链
    • 调用配置的过滤器,然后调用 servlet 的 service() 方法
    • 最后释放过滤器链和 serlvet 实例
    • 如果 servlet 被标记不可用,调用它的 destroy() 方法

6. Web 应用程序的部署

部署的过程其实就是解析 xml 实例化对象,并触发和处理容器及组件对应生命周期事件的过程。

在 Tomcat 中,一个 Context 实例就代表一个 Web 应用程序,所以部署的第一步就是创建一个 StandardContext 对象。在创建时 HostConfig 首先会查找 Context 描述符,它可能在两个位置:

  • $CATALINA_BASE/conf/<engine>/<host>/[webappname].xml
  • $CATALINA_BASE/webapps/webappname/META_INF/context.xml

如果两个位置都不存在此文件,则使用 conf/context.xml 默认配置。

Context 实例化后会触发 init 和 start 生命周期事件:

  • init - 会创建用于解析 context.xml 和 web.xml 的工具 Digester 的实例,并解析context.xml
  • start - 则会根据 web.xml 部署描述符实例化 Servlet、Filter、Listener 等 Web 组件

6.1 热部署和热加载

热部署和热加载的操作都是由容器的后台线程调用自身、子容器或组件的 backgroundProcess() 方法或 periodic 生命周期事件触发。

如果 Host 的 autoDeploy 属性为 true,那么在运行时将 Web 应用程序放到 webapps 目录下,会自动部署;此外它还监视 .war、context.xml 和 web.xml 以及docBase 目录下的静态资源文件,如果 lastModified 有变动会重新部署。

如果 Context 的 reloadable 属性为 true,那么 Loader 组件的 backgroundProcess() 方法会检测 class和jar 的变化并自动加载。

7. 小结

本文主要对容器的设计进行了分析,其中核心就是 Lifecycle 和 Pipeline 的设计。接下来会对各个组件的实现进行分析。

Tomcat 容器的设计和实现的更多相关文章

  1. 浅读tomcat架构设计之tomcat容器Container(3)

    浅读tomcat架构设计和tomcat启动过程(1) https://www.cnblogs.com/piaomiaohongchen/p/14977272.html 浅读tomcat架构设计之tom ...

  2. Tomcat剖析(五):Tomcat 容器

    Tomcat剖析(五):Tomcat 容器 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三):连接器(1 ...

  3. Tomcat 容器的安全认证和鉴权

    大量的 Web 应用都有安全相关的需求,正因如此,Servlet 规范建议容器要有满足这些需求的机制和基础设施,所以容器要对以下安全特性予以支持: 身份验证:验证授权用户的用户名和密码 资源访问控制: ...

  4. 初探Tomcat的架构设计

    Tomcat 作为 servlet 容器实现,它是基于 Java 语言开发的轻量级应用服务器.因为 Tomcat 作为应用服务器,它有着完全开源,轻量,性能稳定,部署成本低等优点,所以它成为目前 Ja ...

  5. Tomcat容器、JSP和Servlet

    目录 JSP Tomcat.JSP和Servlet JSP JSP全名为Java Server Pages,其根本是一个简化的Servlet设计.JSP技术有点类似ASP技术,它是在传统的HTML网页 ...

  6. docker:从 tomcat 容器连接到 mysql 容器

    docker 中的容器互联是一个较为复杂的话题,详细内容将在后续章节中介绍. 续前 2 个章节的内容,我们创建了一个 mysql 容器和一个 tomcat 容器,可以使用 「docker ps」来查看 ...

  7. ApplicationContext容器的设计原理

    1.在ApplicationContext容器中,我们以常用的FileSystemXmlApplicationContext的实现为例来说明ApplicationContext容器的设计原理. 2.在 ...

  8. BeanFactory容器的设计原理

    XmlBeanFactory设计的类继承关系 1.BeanFactory接口提供了使用IoC容器的规范.在这个基础上,Spring还提供了符合这个IoC容器接口的一系列容器的实现供开发人员使用. 2. ...

  9. eclipse中建立tomcat容器

    步骤 1.  new - orther - server 出现下图,选择tomcat版本, 2. 选择已有的web项目至tomcat容器中,如果尚未建立,可不选. 3. 点击完成后,就会发现一个新建项 ...

随机推荐

  1. 用PHP开发命令行工具

    介绍 用过laravel开发过项目的都应该用过artisan,通过artisan我们可以在命令行中创建控制器类,Eloquent类等,今天我们将通过php来开发命令行工具 开发环境与工具 使用vagr ...

  2. windows下hadoop安装配置(转载)

    Windows平台安装配置Hadoop 步骤: 1. JDK安装(不会的戳这) 2. 下载hadoop2.5.2.tar.gz,或者自行去百度下载. 3. 下载hadooponwindows-mast ...

  3. Java Minor GC和FullGC

    Minor GC触发条件:当Eden区满时,触发Minor GC. Full GC触发条件: 调用System.gc时,系统建议执行Full GC,但是不必然执行 老年代空间不足 方法去空间不足 通过 ...

  4. JavaScript之搜索框

    啧啧啧,又到月末了,时间过的真的好快啊︿( ̄︶ ̄)︿现在没课上,天天宅在寝室就这么三件事:吃饭睡觉打豆豆.真感无所事事,无聊至极!突然好怀念那些上课的日子啊!至少不像现在,生活状态全部都搅乱了:以前可 ...

  5. linux 环境下 eas console的运行

    1)访问 http://<HOST>:19000/easconsole/ 2)然后下载 jnlp 文件. 3)找个jre, 用javaws 运行 jnlp文件

  6. 微任务、宏任务与Event-Loop

    首先,JavaScript是一个单线程的脚本语言.所以就是说在一行代码执行的过程中,必然不会存在同时执行的另一行代码,就像使用alert()以后进行疯狂console.log,如果没有关闭弹框,控制台 ...

  7. python学习笔记(五)---sublime text 多行代码注释快捷键

    转载网址:https://blog.csdn.net/mycms5/article/details/70194045/ 多行选择后按下ctrl+/ 选择类 Ctrl+D 选中光标所占的文本,继续操作则 ...

  8. Mysql04

    mysql: dbs 数据库系统 bdms 数据库管理系统 bda 数据库管理员 db 数据库 dba通过dbms来操作db! 关系型数据库和非关系型数据库 登录mysql mysql -h主机地址 ...

  9. BootStrap使用

    BootStrap简单使用 <深入理解BootStrap>这本书对BootStrap进行了全面的讲解包括设计思想以及源码解析对没有接触过的很有帮助 BootStrap可以说是最简单的一类框 ...

  10. 20181009-2 选题 Scrum立会报告+燃尽图(01)

    Scrum立会报告+燃尽图(01)选题 此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2190 一.小组介绍 组长:刘莹莹 ...