title: tomcat源码学习日志
date: 2018-07-07 23:32:43
tags:
- tomcat
- 源码学习
categories: 技·术
Tomcat是什么
Tomcat是Servlet
、JSP
、java EL表达式、WebSocket
的实现。
Tomcat 7.0实现了Servlet 3.0
和JSP 2.2
。提供了更多feature来开发和部署web应用和web服务。
官方资源汇总
编译源码
- 下载
Tomcat7
源码 - 配置
JDK1.6
- 配置
1.9.x
版本的Ant - 将build.xml中的
base-apache.loc.1=https://www.apache.org/dyn/closer.lua?action=download&filename=
替换为base-apache.loc.1=https://archive.apache.org/dist
- 在tomcat目录下执行
ant
源码阅读日志
整体理解
- 主类/主方法:
org.apache.catalina.startup
包下的Bootstrap
类。 - 几个重要的目录(或者说环境变量):
主目录 | 含义 |
---|---|
{ $CATALINA_HOME } | Tomcat安装目录 |
{ $CATALINA_BASE } | 每个实例分别的根目录(可选,默认情况等同于{ $CATALINA_HOME }) |
CATALINA_HOME
├─bin // 诸如启动、停止等脚本。
├─conf // 配置文件
├─logs // 默认日志文件路径
└─webapps // web应用路径
架构理解
名称 | 意义 |
---|---|
Server | 代表整个容器。用户基本不会变动它。提供了Server 接口。 |
Service | 作为一个生存在Server 中的组件,将许多Connector 与一个Engine 连接,起媒介作用。 |
Engine | 代表某个Service 的请求过程。一个Service 连接着多个Conntector ,Engine 接收这些Connector 的请求,处理请求,并返回。提供了Engine 接口。 |
Host | 一个Tomcat可包含多个域名,Host则维护这些域名。t提供了Host 接口和完善的实现。 |
Connector | 用于处理与客户端的通信。如Http Connector 。 |
Context | 代表一个Web应用。一个Host 包含多个Context ,分别处于唯一的路径。提供了Context 和完善的实现。 |
按照以上概念可以绘图:
启动步骤
根据官方文档,tomcat启动序列分为两个步骤:1)从命令行启动 2)处理命令行参数
一、从命令行启动
类:org.apache.catalina.startup.Bootstrap
执行内容:
- 安装一系列
classLoader
; - (以反射)读取启动类;
- 完成
Bootstrap.daemon.init()
方法。
二、处理命令行参数(start,stop)
类:org.apache.catalina.startup.Bootstrap
执行内容(start):
Catalina.setAwait(true)
;Catalina.load()
:- 初始化基本文件夹:
initDirs()
-> 设置诸如catalina.home/case
等属性; - 初始化命名服务:
setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY,org.apache.naming.java.javaURLContextFactory ->default)
- 创建xml文件转化器:
createStartDigester()
- 读取
server.xml
并用转化器(digester)将其解析。digester是一个“XML-对象”映射器,将根据server.xml
定义的内容创建对象。到目前为止,容器其实还没有开始初始化。 - 把
System.out
和System.err
分配给SystemLogHandler
类。 - 调用所有组件的初始化方法。此步骤将令每个对象通过
JMX
代理注册其本身。在此步骤中,Connector
也将初始化适配器。适配器也是一种组件,用来执行请求预处理。例如HTTP1.1适配器:org.apache.coyote.http11.Http11Protocol
- 初始化基本文件夹:
Catalina.start()
:- 启动
NamingContext
,将所有JNDI
引用绑定其中。 - 启动
Server
下的所有service
。此步骤启动引擎(Engine)。 - 启动主机:
StandardHost
。- 配置一个错误阀门,用于将不同的HTTP错误码为HTML。
- 设置标准主机阀门,将web应用的类加载器与线程上下文绑定,它也用来为请求找到相应的
session
。 - 启动
HostConfig
组件。此组件部署所有web应用,即webapp
和conf/Catalina/localhost/*.xml
HostConfig
将为上下文创建一个Digester
,它将调用ContextConfig.start()
。这个方法将处理默认的web.xml
即conf/web.xml
,然后处理所有的应用web.xml
即WEB-INF/web.xml
。
- 在容器的生命周期中,存在一个后台线程,用来不断检查上下文(context)是否改变,即
war
文件、context
文件、web.xml
文件等的改变。如果改变,则重新加载。(stop/remove/deploy/start
)
- 启动
- 当Tomcat(在HTTP端口)接收到一个请求时:
- 该请求将被一个独立的线程接收。此线程在
ThreadPoolExecutor
类中。它在一个ServerSocket.accpet()
方法中等待请求。 ThreadPoolExecutor
分配一个TaskThread
来处理此请求。- 处理器(
processor
)处理该请求。如果是HTTP请求,则是Coyote Http11Processor
来处理。调用了process
方法。此处理器将继续检查socket
的输入流,直到连接断开,或者达到keep alive point
。 - 此HTTP请求将被内部的缓冲类(
Http11InputBuffer
)解析。此解析类将解析出请求行、请求头等等,将结果存储在一个Coyote
请求中。此request
包含所有的HTTP信息,如servername
,port
,scheme
等。 - 处理器维护着一个
Adapter
(引用),在本例中是CoyoteAdapter
。一旦请求已经被解析,那么Http11Processor
调用该adapter
的service()
方法。在此service
方法中,Request
包含一个CoyoteRequest
和一个CoyoteResponse
(第一次则为null)。CoyoteRequest(Response)
实现了HttpRequest(Response)
和HttpServletRequest(Response)
。适配器通过Mapper
来处理request
和context
等。 - 当解析完成之后,
CoyoteAdapter
调用它的容器(StandardEngine
),调用所有的invoke()
方法。 StandardEngine.invoke()
方法调用容器的pipeline.invoke()
方法。StandardHostValve
调用与request
相关的context
上的pipeline
。- 被
Context pipeline
调用的第一个阀门是FormAuthenticator
阀门。接下来是StandardContextValve
。StandardContextValve
调用与context
相关的所有上下文监听器。然后调用Wrapper
组件的所有pipeline
。 - 编译JSP,调用实际的
servlet
。
- 该请求将被一个独立的线程接收。此线程在
servlet
类的调用
优美代码
观察到,一个典型的类中,可以被分成:
// ------------------------------------------------------- Static Variables
// -------------------------------------------------------------- Variables
// -------------------------------------------------------- Private Methods
// ----------------------------------------------------------- Main Program
典型的生命周期方法有:
public void init()
public void init(String[] arguments)
public void start()
public void stop()
public void stopServer()
public void stopServer(String[] arguments)
public void destroy()