tomcat架构分析(容器类)
Tomcat提供了engine,host,context及wrapper四种容器。在总体结构中已经阐述了他们之间的包含关系。这四种容器继承了一个容器基类,因此可以定制化。当然,tomcat也提供了标准实现。
- Engine:org.apache.catalina.core.StandardEngine
- Host: org.apache.catalina.core.StandardHost
- Context:org.apache.catalina.core.StandardContext
- Wrapper:org.apache.catalina.core.StandardWrapper
所谓容器,就是说它承载了若干逻辑单元及运行时数据。好比,整个酒店是一个容器,它包含了各个楼层等设施;每个楼层也是容器,它包含了各个房间;每个房间也是容器,它包含了各种家电等等。
首先来看一下容器类的类结构。 
基类ContainerBase
ContainerBase是个abstract基类。其类路径为:
这里只列出一些比较核心功能的组件及方法。需要注意的是,类中的方法及属性很多,限于篇幅不全部列出来了。
Enigne
Engine是最顶层的容器,它是host容器的组合。其标准实现类为:
看一下StandardEngine的主要逻辑单元概念图。

从图中可以看出,engine有四大组件:
- Cluster: 实现tomcat集群,例如session共享等功能,通过配置server.xml可以实现,对其包含的所有host里的应用有效,该模块是可选的。其实现方式是基于pipeline+valve模式的,有时间会专门整理一个pipeline+valve模式应用系列;
- Realm:实现用户权限管理模块,例如用户登录,访问控制等,通过通过配置server.xml可以实现,对其包含的所有host里的应用有效,该模块是可选的;
- Pipeline:这里简单介绍下,之后会有专门文档说明。每个容器对象都有一个pipeline,它不是通过server.xml配置产生的,是必须有的。它就是容器对象实现逻辑操作的骨架,在pipeline上配置不同的valve,当需要调用此容器实现逻辑时,就会按照顺序将此pipeline上的所有valve调用一遍,这里可以参考责任链模式;
- Valve:实现具体业务逻辑单元。可以定制化valve(实现特定接口),然后配置在server.xml里。对其包含的所有host里的应用有效。定制化的valve是可选的,但是每个容器有一个缺省的valve,例如engine的StandardEngineValve,是在StandardEngine里自带的,它主要实现了对其子host对象的StandardHostValve的调用,以此类推。
配置的例子有:
需要注意的是,运行环境中,pipeline上的valve数组按照配置的顺序加载,但是无论有无配置定制化的valve或有多少定制化的valve,每个容器缺省的valve,例如engine的StandardEngineValve,都会在数组中最后一个。
Host
Host是engine的子容器,它是context容器的集合。其标准实现类为:
StandardHost的核心模块与StandardEngine差不多。只是作用域不一样,它的模块只对其包含的子context有效。除此,还有一些特殊的逻辑,例如context的部署。Context的部署还是比较多的,主要分为:
- War部署
- 文件夹部署
- 配置部署等
有时间单独再说吧。照例贴个核心模块概念图。 
Context
Context是host的子容器,它是wrapper容器的集合。其标准实现类为:
应该说StandardContext是tomcat中最大的一个类。它封装的是每个web app。
看一下StandardContext的主要逻辑单元概念图。 
Pipeline,valve,realm与上面容器一样,只是作用域不一样,不多说了。
- Manager: 它主要是应用的session管理模块。其主要功能是session的创建,session的维护,session的持久化(persistence),以及跨context的session的管理等。Manager模块可以定制化,tomcat也给出了一个标准实现;
manager模块是必须要有的,可以在server.xml中配置,如果没有配置的话,会在程序里生成一个manager对象。
- Resources: 它是每个web app对应的部署结构的封装,比如,有的app是tomcat的webapps目录下的某个子目录或是在context节点配置的其他目录,或者是war文件部署的结构等。它对于每个web app是必须的。
- Loader:它是对每个web app的自有的classloader的封装。具体内容涉及到tomcat的classloader体系,会在一篇文档中单独说明。Tomcat正是有一套完整的classloader体系,才能保证每个web app或是独立运营,或是共享某些对象等等。它对于每个web app是必须的。
- Mapper:它封装了请求资源URI与每个相对应的处理wrapper容器的映射关系。
以某个web app的自有的web.xml配置为例;
Xml代码
<servlet-mapping>
<servlet-name>httpserver</servlet-name>
<url-pattern>/*.do</url-pattern>
</servlet-mapping>
对于mapper对象,可以抽象的理解成一个map结构,其key是某个访问资源,例如/*.do,那么其value就是封装了处理这个资源TestServlet的某个wrapper对象。当访问/*.do资源时,TestServlet就会在mapper对象中定位到。这里需要特别说明的是,通过这个mapper对象定位特定的wrapper对象的方式,只有一种情况,那就是在servlet或jsp中通过forward方式访问资源时用到。例如,
Java代码
关于mapper机制会在一篇文档中专门说明,这里简单介绍一下,方便理解。如图所示。

Mapper对象在tomcat中存在于两个地方(注意,不是说只有两个mapper对象存在),其一,是每个context容器对象中,它只记录了此context内部的访问资源与相对应的wrapper子容器的映射;其二,是connector模块中,这是tomcat全局的变量,它记录了一个完整的映射对应关系,即根据访问的完整URL如何定位到哪个host下的哪个context的哪个wrapper容器。
这样,通过上面说的forward方式访问资源会用到第一种mapper,除此之外,其他的任何方式,都是通过第二种方式的mapper定位到wrapper来处理的。也就是说,forward是服务器内部的重定向,不需要经过网络接口,因此只需要通过内存中的处理就能完成。这也就是常说的forward与sendRedirect方式重定向区别的根本所在。
看一下request.getRequestDispatcher(url) 方法的源码。
红色部分标记了从context的mapper对象中定位wrapper子容器,然后封装在一个dispatcher对象内并返回。通过上面的阐述,也说明了为什么forward方法不能跨context访问资源了。
Wrapper
Wrapper是context的子容器,它封装的处理资源的每个具体的servlet。其标准实现类为:
应该说StandardWrapper是tomcat中比较重要的一个类。初认识它时,比较容易混淆。
先看一下StandardWrapper的主要逻辑单元概念图。 
Pipeline,valve与上面容器一样,只是作用域不一样,不多说了。
主要说说servlet对象与servlet stack对象。这两个对象在wrapper容器中只存在其中之一,也就是说只有其中一个不为空。当以servlet对象存在时,说明此servlet是支持多线程并发访问的,也就是说不存在线程同步的过程,此wrapper容器中只包含一个servlet对象(这是我们常用的模式);当以servlet stack对象存在时,说明servlet是不支持多线程并发访问的,每个servlet对象任一时刻只有一个线程可以调用,这样servlet stack实现的就是个简易的线程池,此wrapper容器中只包含一组servlet对象,它的基本原型是worker thread模式实现的。
那么,怎么来决定是以servlet对象方式存储还是servlet stack方式存储呢?其实,只要在开发servlet类时,实现一个SingleThreadModel接口即可。
如果需要线程同步的servlet类,例如:
但是值得注意的是,这种同步机制只是从servlet规范的角度来说提供的一种功能,在实际应用中并不能完全解决线程安全问题,例如如果servlet中有static数据访问等,因此如果对线程安全又比较严格要求的,最好还是用一些其他的自定义的解决方案。
Wrapper的基本功能已经说了。那么再说一个wrapper比较重要的概念。严格的说,并不是每一个访问资源对应一个wrapper对象。而是每一种访问资源对应一个wrapper对象。其大致可分为三种:
- 处理静态资源的一个wrapper:例如html,jpg等静态资源的wrapper,它包含了一个tomcat的实现处理静态资源的缺省servlet:
Java代码
org.apache.catalina.servlets.DefaultServlet
- 处理jsp的一个wrapper:例如访问的所有jsp文件,它包含了一个tomcat的实现处理jsp的缺省servlet:
Java代码
org.apache.jasper.servlet.JspServlet
- 处理servlet的若干wrapper:它包含了自定义的servlet对象,就是在web.xml中配置的servlet。
需要注意的是,前两种wrapper分别是一个,主要是其对应的是DefaultServlet及JspServlet。这两个servlet是在tomcat的全局conf目录下的web.xml中配置的,当app启动时,加载到内存中。
tomcat架构分析(容器类)的更多相关文章
- tomcat架构分析 (Session管理)
Session管理是JavaEE容器比较重要的一部分,在app中也经常会用到.在开发app时,我们只是获取一个session,然后向session中存取数据,然后再销毁session.那么如何产生se ...
- tomcat架构分析-索引
出处:http://gearever.iteye.com tomcat架构分析 (概览) tomcat架构分析 (容器类) tomcat架构分析 (valve机制) tomcat架构分析 (valve ...
- tomcat架构分析(connector BIO 实现)
出处:http://gearever.iteye.com 在tomcat架构分析(概览)中已经介绍过,connector组件是service容器中的一部分.它主要是接收,解析http请求,然后调用本s ...
- tomcat架构分析 (connector NIO 实现)
出处:http://gearever.iteye.com 上一篇简单记录了缺省配置的connector的内部构造及消息流,同时此connector也是基于BIO的实现.除了BIO外,也可以通过配置快速 ...
- tomcat架构分析(valve源码导读)
出处:http://gearever.iteye.com 源码面前,了无秘密 ----侯捷 在tomcat架构分析(valve机制)(http ...
- tomcat架构分析(概览)
出处:http://gearever.iteye.com Tomcat是目前应用比较多的servlet容器.关于tomcat本身的特点及介绍,网上已经有很多描述了,这里不再赘述.Tomcat除了能够支 ...
- tomcat架构分析和源码解读
最近在看<深入分析java web技术内幕>,书中讲解了一部分tomcat的相关知识,我也去查看了一些源码,看了大神们写的代码,我才知道自己就像在做加减乘除一样,这是不行的.还有好多包和类 ...
- tomcat架构分析(valve机制)
关于tomcat的内部逻辑单元的存储空间已经在相关容器类的blog里阐述了.在每个容器对象里面都有一个pipeline及valve模块. 它们是容器类必须具有的模块.在容器对象生成时自动产生.Pipe ...
- tomcat架构分析及配置详解
浏览器访问服务器的流程 请求发起的过程: 注意:浏览器访问服务器使用的是http协议,http是应用层协议,而具体传输还是使用的TCP/IP协议 Tomcat系统总架构 2.1 Tomcat请求处理过 ...
随机推荐
- JAVA遍历Map的方法
import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class TestMap { pu ...
- HTTP协议详解之User Agent篇
•User Agent:用户代理 指浏览器他的信息包括硬件平台.系统软件.应用软件和用户个人偏好.用户代理不仅仅指浏览器,还包括搜索引擎. •为什么所有浏览器的User Agent都带有Mozilla ...
- 24、java操作xml方法
XML解析方式 1. SAX解析方式 SAX(simple API for XML)是一种XML解析的替代方法.相比于DOM,SAX是一种速度更快,更有效的方法.它逐行扫描文档,一边扫描一边解析.而且 ...
- 腾讯云-搭建 .NET Core 开发环境
搭建 .NET Core 开发环境 安装 .Net Core 执行代码 任务时间:时间未知 .NET Core 的官方文档很详细,本实验带你建立一个.NET Core 1.1的Web运行环境,更多内容 ...
- Android SharedPreferences保存和读取对象
SharedPreferences保存和读取对象 1.首先要序列化对象(以下是序列化实体类的样例,不方便贴出实体类全部的代码) public class LoginResult extends Bas ...
- delphi實現按键精靈的功能
unit kbKernel; interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Fo ...
- word中批量修改图片大小
一,在word中按alt+f11组合键,进入VBA模式二,在左边的工程资源管理器中找到你的word文档,在其上右键/添加/模块三,把下面代码复制,粘贴进去.四,更改数值, 改一下宽度和高度数值(10) ...
- 关于android.view.WindowLeaked(窗体泄露)的解决方案
虽然是小问题一个,但也困扰了我一段时间,现在记下来,给自己做个备忘,也可以给其他人一个参考 view plaincopy to clipboardprint? 01-08 01:49:27.874: ...
- Java中堆内存和栈内存详解【转】
Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...
- Android广播BroadcastReceiver
Android 系统里定义了各种各样的广播,如电池的使用状态,电话的接收和短信的接收,开机启动都会产生一个广播.当然用户也可以自定义自己的广播. 既然说到广播,那么必定有一个广播发送者,以及广播接收器 ...