1
前言
Tomcat
是一个
servlet
容器,它是
Java Servlet
和
JavaServer Pages
技
术
的官方参考
实现
。
Tomcat
是在
Apache Software License
下
开发
和
发
布的一个
开
放源
码
的
项
目。在本文做成
时
Tomcat
的主要版本是
Tomcat 5.0.2 Alpha
版
实现
了
Servlet2.4/JSP2.0
规
范和
Tomcat4.1.24
版
实现
了
Servlet2.3/JSP1.2
规
范。由于
Tomcat5.x
还处
在
开发阶
段没有正式
发
布。所以我
们
主要分析
Tomcat4.x
版。
Tomcat4.1.24
是最近的
release
版。
Tomcat4.1
是在
Tomcat4.0.x
(
Tomcat3.x
后重写的核心称
为
Catalina
)基
础
上重构的,在很多方面有
显
著的增
强
:
l
基于
JMX
的管理特性
l
基于
JSP
和
Struts
的
Web admin
管理
应
用
l
新的
Coyote
连
接器
,
支持
HTTP/1.1,AJP1.3
和
JNI
l
重新
编
写了
JSP page
编译
器
Jasper
l
性能表
现
和内存效率
显
著的提高
l
增
强
的
manager
应
用程序支持和
开发
工具集成
l
在
build.xml
脚本中自定
义
的
Ant
任
务
可以和
manger
应
用程序
发
生交互
为
了帮助大家更快地
阅读
和学
习
Tomcat
的源
码
,本文
针对
Tomcat4.1.24
进
行一些介
绍
,包括它的基本
结
构、核心的
对
象、
简单
的启
动
和
处
理
请
求的流程。希望可以帮助大家更好的理解
Tomcat
,
步
入到
Tomcat
这
个
开
放源
码
的世界中。
2 server.xml
配置文件中的结构和概念
[2]
理解
Tomcat
首先要了解的是配置文件
server.xml
。
Tomcat
中
conf/server.xml
文件是最
为
重要的,通
过
它可以描述
Tomcat
的
结
构和配置
Tomcat
的行
为
。下面就
对该
文件
进
行介
绍
。
server.xml
文件描述了整个
Tomcat
的基本
结
构,
该
文件中所有的元素
对应
Tomcat
中核心
软
件
组
件
对
象,
这
些
组
件分成下面的几
类
,我
对
它
们进
行
简单
的介
绍
:
l
最高
层
元素:
:
表示整个
Catalina Servlet
容器。它是
server.xml
中的根元素。
:表示一个或者多个
Connector
共享一个
Engine
来
处
理客
户请
求的
组
合。一个
server
元素可以包含多个
service
元素。
l
连
接元素
Connector
:表示外部的客
户
和特定
Service
之
间发
送
请
求(或接受响
应
)的接口。
JTC
是
Jakarta-Tomcat-Connectors
的
缩
写。它包括两
种
不同
类
型的
Connector
。一
种
允
许
browser
直接
连
接到
Tomcat
,另一
种
是通
过连
到其他的
Web Server
实现
。如下的元素都是
连
接器:
、
属于直接
连
接的
Connector
。是最新的
连
接器。不再推荐使用。
、、
属于
连
接其他
Web Server
的
Connector
。是最新的
连
接器。
l
容器元素
Containers
:表示具有
处
理
输
入
请
求和
产
生相
应
响
应
的功能
组
件。如下的元素都属于容器元素
:表示了在特定的
Catalina Service
中整个
请
求
处
理的机制。它从
Connector
接受
请
求,
处
理,然后返回响
应
到
Connector
。它可以包含多个
Host
元素。
:表示特定的运行
Tomcat
服
务
的网
络
虚
拟
主机。可以包含多个
Context
元素。
:表示一个具体的
Web
应
用。运行在指定的虚
拟
主机中。
l
嵌入元素:所有可以嵌入在容器元素中的元素。如下的元素都属于嵌入元素
:表示在
Server
中定
义
的全局
JNDI
资
源
:表示
为
web
应
用加
载
Java
类
和
资
源的特定的
class loader
对
象
:表示容器元素
输
出
log
信息、
debug
信息和
错误
信息的
对
象
:表示
为
web
应
用
创
建和管理
HTTPsession
的
对
象
:表示容器中
关
于用
户
名、密
码
和角色的数据
库
信息的
实现
:表示
web
应
用中的静
态资
源。
这
些
资
源可以被
class
、
HTML
、
JSP
等使用
:表示在容器的
Pipeline
中被
调
用的
处
理
组
件(有
关
Pipeline
和
valve
设计
概念下面会有
详细
介
绍
)
图
一是
Catalina
的
结
构
简图
希望可以帮助大家理解
图
一
catalina
结
构
简图
l
注意:所有在
server.xml
中描述的元素在
Tomcat
的
实现
中都会有相
应
的
java
接口定
义
和相
应
的
标
准
实现
,例如元素在程序中的
实现
包括接口
Server.java
和
标
准
实现
StandardServer.java
。了解
这
一点
对
于
阅读
和理解
Tomcat
的源
码
非常有帮助。
Catalina
源码分析
3
.
1 Catalina
核心源码的目录结构
解
压
Tomcat4.1.24
源
码
包后在
catalina/src/share/org/apache/catalina/
目
录
下包含了
catalina
的源
码
。(
Java
的包名和路径名是
对应
的,
为
了便于找到源文件我直接使用路径名)
每
个子目
录
从命名上就可以猜出它的基本含
义
,并且在目
录
中基本上都有一个
package.html
文件描述了
这
个目
录对应
的包所完成的主要功能。
刚开
始
阅读
源
码
的
时
候,我
们
可以从
/startup
子目
录
中
开
始。
这
个包中包含了如何启
动
Tomcat
。然后可以
开
始看
/core
包中的文件,
这
个包
实现
了
Catalina
的核心
对
象。
进
一
步
可以
开
始看在核心
对
象
处
理
时
使用的相
关
功能的具体
实现
。
这
些功能都
对应
有相
应
的包。下面一个小
节
会介
绍
在
Catalina
设计
是所使用的一个主要的模式,了解了
这
个模式
对阅读
和理解
Tomcat
的源
码
非常的重要。
3
.
2 Catalina
的主要设计模式
在
Catalina
的
设计
中所有的容器元素都派生于抽象的
Container
接口。在
每
个
Container
的
实现
中都会使用一个
Pipeline
对
象。
Pipeline
对
象被
Container
用于
实现对
接收到的
请
求
进
行
处
理的机制。利用的是
责
任
链
(Chain of Responsibility)
设计
模式
[5][6]
。
每
个
Container
把自己的
处
理功能封装到
Valve
对
象中,并且把
这
个
Valve
对
象配置到自己的
Pipeline
中。下面具体解
释
一下。
在
这
个模式中主要的使用的是以下的接口:
Pipeline
、
Valve
和
ValveContext
Pipeline
接口:定
义
了当
invoke()
方法被容器
调
用
时
,一
组
Valve
被
顺
序的
调
用,并且要求在
Pipeline
中的必
须
存在一个
Valve
(通常是最后一个)
对请
求
进
行
处
理并
产
生响
应
,而不能将
请
求跳
过
。
每
一个容器都包含一个
Pipeline
实
例,通
过
setBasic()
方法,容器自身的
处
理
过
程被封装成容器特定的
Valve
,并且被放在
Pipeline
的最后
执
行。在自身特定
逻辑
的
处
理
Valve
被
执
行前,另外加入的其他功能
Valve
被按照加入的
顺
序
执
行。(
这
个是通
过
在
server.xml
文件中配置容器元素中的嵌入元素
实现
的。)
Valve
接口:定
义
了容器的
请
求
处
理
组
件。在
invoke()
方法中
实现
具体的
请
求
处
理
逻辑
。
ValveConext
接口:提供了一
种
机制,使得一个
Valve
可以触
发
Pipeline
中下一个
Valve
进
行
业务处
理,而
这种
机制的
对
Valve
本身来
说
是透明的。
ValveContext
实
例在
Valve
的
invoke()
调
用
时
是作
为
参数
进
行
传递
。(
这种
机制本身
实现
起来是比
较简单
的,
ValveContext
实现类
可以通
过
Pipeline.getValves()
访问
得到所有的
Valve
对
象,在
invoke()
调
用后
记录
当前
调
用的
Valve
对
象的位置并向下
传递
即可。)
这
个模式
贯
穿了
Catalina
中所有容器
对
象的
实现
当中,
图
二是
这
个模式中主要接口的
设计
正确的理解
这
个模式的
实现
和
设计
可以帮助我
们
更好的
阅读
Catalina
的源
码
。
图
二
Catalina
中
Pipeline Valve
的静
态图
在
Catalina
中
还
大量的使用了
Java Event
模型,包括生存期事件、属性
变
更事件等多
种
事件。
关
于
Java Event
模型
这
里不多介
绍
了,有
兴
趣的参考下面的文献
[4]
在
Catalina
中另一个比
较
需要注意的地方是大量使用了
apache
项
目中的子
项
目尤其是
Jakarta Commons
项
目,例如
Digester,logger
等等。所以了解
Tomcat
中使用的
Commons
有
关项
目的内容和使用方法是十分有必要的。有
关
的信息参考下面的文献
[3]
3
.
3 Catalina
的核心对象
Catalina
的核心
对
象就是
对应
server.xml
文件的
实现
,有
关
的源
码
在
catalina/src/share/org/apache/catalina
和
catalina/src/share/org/apache/catalina/core
目
录
下。
Server.xml
中的元素都
对应
有相
应
的接口定
义
和
标
准
实现
。
每
个元素的功能通
过这
些
java
对
象得到
实现
。
在
Server.xml
中没有描述的一个核心
对
象是
Wrapper
对
象,它是与
conf/web.xml
配置文件相
关
的。
Wrapper
表示通
过
web.xml
文件定
义
的独立的
servlet
对
象。通
过
Wrapper
的封装,使得我
们
可以完成
对
底
层
的具体
servlet
对
象的各
种
管理的抽象
统
一接口。
Wrapper
是最小的
组
件不能再有子容器,它的上
级
容器可以是
Context
。通
过
conf/web.xml
文件的配置把
请
求按照
类
型
对应
到特定的
Wrapper
封装的
servlet
实现
上
进
行
处
理。由于
Wrapper
比
较
特
别
,所以它不再是前面意
义
上的容器
对
象。也没有出
现
在
server.xml
配置文件中。
所有的
Container
元素都从
Container
接口派生,嵌入的具体
Valve
功能
组
件都从
Contained
和
Valve
接口派生。他
们
的
结
构和行
为
都是相同的,所不同只是在具体的
逻辑处
理上的不同。所以
Catalina
的核心
对
象在
设计
上有着高度的抽象
统
一,非常便于分析和理解。
图
三
Catalina
核心的主要
对
象的一个
简单
的
uml
静
态图
。从
竖
的方向上看,描述的是接口、
标
准
实现
和
该对
象的
逻辑处
理的
Valve
对
象以及用于帮助容器
选择
合适的子容器
进
行
进
一
步处
理的
辅
助
对
象
Mapper
。具体的
实现
我
们
可以参考
这
个
图
去
阅读
源
码
。
图
三
Catalina
的核心
对
象
3
.
4 Catalina
的启动
Tomcat
服
务
器启
动
的方式比
较简单
,
涉
及的
对
象也比
较
少。有
关
的源
码
在
catalina/src/share/org/apache/catalina/startup
目
录
下。我
们
可以参考
图
四
进
行
阅读
。
图
四
Catalina
的启
动对
象
Tomcat
的启
动
是通
过创
建一个
Digester
对
象,解析
server.xml
文件完成有
关
的
Tomcat
功能
对
象加
载
的,
关
于
Digester
具体的使用
见
参考
[5]
。在
这
些有
关对
象被加
载
和
创
建之后,
Catalina
对
象
发
Start()
消息,
Tomcat
的核心
组
件启
动进
入服
务
状
态
。
图
五是一个
Tomcat
启
动
的
简单时
序
图
。在表示用于
处
理多个
连
接
请
求的工作者
线
程方面有些
简
化。可以参照
图
中的
步骤
分析
Tomcat
的源
码
。
图
五
Tomcat
启
动
的
简单时
序
图
3
.
5 Catalina
的对客户请求的响应
上一小
节
介
绍
了
Tomcat
启
动
的基本
过
程。
这
一小
节
介
绍
Tomcat
如何
处
理客
户
端的
请
求。在
Tomcat
处
理客
户请
求
时涉
及到的
对
象比
较
多,包括有
关
客
户连
接建立的
处
理、服
务线
程的管理和
请
求内容的
处
理。有
关连
接的建立和服
务线
程的管理可以我的文章参考
[7]
有相
应
的介
绍
。
这
里主要介
绍
客
户请
求的
处
理。
Tomcat
内部是按照逐
步
分解的方式
对
客
户
端
请
求
进
行
处
理的。例如:
StandardEnigeValve
根据
请
求所携
带
的
server name
信息来
调
用相
应
的
StandardHostValve
进
一
步处
理,
StandardHostValve
根据
请
求的
url
中的
context
信息
选择
合适的
StandardContextValve
进
行
处
理,如此
继续
分解,直到最后通
过
Wrapper
对
象根据具体的
请
求
类
型和内容
选择
合适的
servlet
提供相
应
的服
务
。
这
里主要
涉
及的是
Valve
,
Pipeline
,
Mapper
和
Wrapper
对
象
每
个容器在使用
Pipeline,Valve
,
Mapper
进
行
处
理
时
流程都是一
样
的。了解到
这
一点
对
源
码
的分析大有好
处
。
图
六是一个客
户请
求的
简
化
时
序
图
。可以按照它的
步骤
分析
Tomcat
的源
码
。
图
六
一个客
户请
求的
简
化
时
序
图
写在最后
本文主要介
绍
了
Tomcat
的核心
对
象的
结
构和
组织
方式,以及
简
化的启
动
和
请
求
处
理的流程。目的是
为
了
给阅读
Tomcat
源
码
提供一个起点和思路,所以全文比
较简单
。在
Tomcat
中有很多
java
最新技
术
的体
现
和
应
用,如
JMX
、
JNDI
、
CLUSTER
和采用
MVC
架构
实现
的管理
应
用程序等等都
值
得我
们
学
习
和借
鉴
。通
过对
Tomcat
源
码
的
阅读
和研究可以使我
们
的学
习
和工作受益良多。
参考文献
[4]Java Event
机制
简
介
:
http://www-900.ibm.com/developerWorks/cn/cnedu.nsf/java-onlinecourse-bytitle/C1A25BE6363089CB48256BA70012BB39?OpenDocument