# Tomcat源码学习
**Repository Path**: xingmulee/tomcat-source-code-learning
## Basic Information
- **Project Name**: Tomcat源码学习
- **Description**: 学习阅读Tomcat源码
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 20
- **Created**: 2022-07-25
- **Last Updated**: 2024-08-15
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 学习笔记
1. [搭建Tomcat源码阅读环境,无bug运行调试。](https://stefan.blog.csdn.net/article/details/117620726)
2. [Tomcat的启动与关闭:详解启动类Bootstrap和Catalina,彻底搞懂catalina.home和catalina.base的区别和作用范围](https://stefan.blog.csdn.net/article/details/117856646)
3. [Tomcat如何快速响应静态资源(DefaultServlet+浏览器缓存)](https://stefan.blog.csdn.net/article/details/117126078)
持续更新中…
## Tomcat架构


## 搭建源码阅读环境
阅读学习Tomcat源码,需要三件事:
1. 看书入门,这里推荐两本关于Tomcat的书《Tomcat内核设计剖析》汪建 和《Tomcat架构解析》刘光瑞。
2. 搭建Tomcat源码运行环境,并debug。
3. 阅读[Tomcat最新源码](https://github.com/apache/tomcat ),多版本比对源码。Tomcat在`Github`中开源,可`git clone` 最新代码到本地。阅读最新源码有一个好处就是可以看到参与Tomcat开发大佬的提交记录。
## 运行Tomcat源码
### 1、下载源码
`Tomcat`各版本源码:[https://archive.apache.org/dist/tomcat/](https://archive.apache.org/dist/tomcat/)
`Tomcat`安装包:[https://tomcat.apache.org/](https://tomcat.apache.org/)
为什么又要下载源码,又要下载安装包?源码中`webapps`是没有编译的,需要用安装包里的替换,并且`Tomcat`用的是`ant+build.xml`依赖管理,这种方式比较老,现在都用`maven`、`gradle`了,所以可以手动换成`maven`,但是有些包在`maven`仓库中找不到,可以从`Tomcat`安装包`lib`目录下获取。
我这里下载的是两个版本,`Tomcat8.5.9`和`Tomcat`最新版本(10.0.6),后面会分别讲解两个版本的源码运行搭建方式。
### 2、Tomcat8.5.9源码运行
下载好的`apache-tomcat-8.5.9-src`,用IDEA打开并引入:File–>Project Structure–>Modules–>+–>import module。

#### (1)新建pom.xml
```xml
4.0.0
org.apache.tomcat
Tomcat8.5.9
Tomcat8.5.9
8.5.9
Tomcat8.5.9
java
java
test
org.apache.maven.plugins
maven-compiler-plugin
2.3
UTF-8
1.8
1.8
junit
junit
4.12
test
org.easymock
easymock
3.4
ant
ant
1.7.0
wsdl4j
wsdl4j
1.6.2
javax.xml
jaxrpc
1.1
org.eclipse.jdt.core.compiler
ecj
4.5.1
```
#### (2)替换webapps和加 lib 包
因为源码包`webapps`下示例项目`WEB-INF/classes/`下的`.java`没有编译,没有.class文件,所以可将整个`webapps`删除,并复制安装包中的`webapps`到源码包。
源码包中新建lib目录,从安装包中的lib目录复制`jasper.jar`到源码包的lib目录。这样做的目的有两个:
- Tomcat运行时会默认扫描lib目录,没有lib目录虽然不会报错,但是控制台会有警告日志,提示lib目录不存在。
- 安装包lib下jar包很多,没必要都复制过来,按需复制了`jasper.jar`,虽然`jasper.jar`中的代码和源码中的`org.apache.jasper`完全重了,但是这个jar包里有非常重要的配置信息,定义了`javax.servlet.ServletContainerInitializer`的实现类是`org.apache.jasper.servlet.JasperInitializer`,`Tomcat`启动时,`Context`的生命周期监听器`ContextConfig.configureStart`会扫描lib目录下的jar里面的配置信息,做一些类初始化等操作。这里就是主动实例化`JasperInitializer`,不然访问`jsp`就会报错。(百度到的都是在源码里写死加一个`JasperInitializer`的初始化,不推荐这样做,一定要找到原因。)

#### (3)运行Bootstrap#main
`org.apache.catalina.startup.Bootstrap#main` 是`Tomcat`一键启停的源头,运行这个`main`方法之前需要指定一下配置的位置,`Tomcat`必须要引用`server.xml`等配置才可以运行起来。
需要先了解两个概念:
- `catalina.home`是`web`项目部署目录。
- `catalina.base`是`Tomcat`安装目录。
一般情况这两个目录设置成一样的,`Tomcat`读的一些配置,默认都是在这两个目录下,比如`conf`、`webapps`、`lib`等。我这里`VM options`设置了`catalina.home`和`catalina.base`都是源码目录,并指定了`Log`的配置。
```
-Dcatalina.home=C:/study/tomcat/apache-tomcat-8.5.9-src
-Dcatalina.base=C:/study/tomcat/apache-tomcat-8.5.9-src
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=C:/study/tomcat/apache-tomcat-8.5.9-src/conf/logging.properties
```

#### (4)运行并访问
完成以上三步,就可以运行了:

如果`test`目录有报错,可删除报错的位置(最好不要删除整个`test`目录,可以自己在`test`目录里写测试类`debug`)。正常运行后,在浏览器中访问http://127.0.0.1:8080/ , 点击页面中的超链接如`Documentation`、`Configuration`等都可以正常访问。


#### (5)-config指定配置路径运行
`webapps`下的web项目是会自动部署的,但是实际生产中,不太可能让所有的web项目都部署在`webapps`下,不太可能启动一个`Tomcat`,运行所有web,一旦一个web运行异常导致Tomcat挂了,其他web也会受到影响。所以一般通过`-config`指定配置,一个web运行一个`Tomcat`,保证进程隔离。(`VM options`不要更改)
```xml
# Program arguments, example1.conf是定制的server.xml配置
-config C:/study/tomcat/conf/example1.conf start
```

example1.conf:
```xml
```
### 3、Tomcat10.0.6源码运行
和`apache-tomcat-8.5.9-src`的过程差不多,稍有不同的地方是一些依赖需要调整。(`Tomcat10.0.6`中直接复制整个安装包的lib到源码包中运行不会报错,所以直接整个lib复制过去)
`pom.xml`比8.5.9多两个依赖`jakartaee-migration`和`biz.aQute.bndlib`:
```xml
4.0.0
org.apache.tomcat
Tomcat10.0.6
Tomcat10.0.6
10.0.6
Tomcat10.0.6
java
java
test
org.apache.maven.plugins
maven-compiler-plugin
2.3
UTF-8
1.8
1.8
junit
junit
4.12
test
org.easymock
easymock
3.4
ant
ant
1.7.0
wsdl4j
wsdl4j
1.6.2
javax.xml
jaxrpc
1.1
org.apache.tomcat
jakartaee-migration
1.0.0
biz.aQute.bnd
biz.aQute.bndlib
5.3.0
provided
```
依赖中去掉了`ecj`,因为这个依赖maven仓库中最新版本也满足不了`Tomcat10.0.6`,需要从`Tomcat10.0.6`的安装包lib中复制`ecj-4.18.jar`到源码包的lib下,同时需要手动指定依赖:

依赖调整好以后,其他操作都和`apache-tomcat-8.5.9-src`一样。但是运行10.0.6后控制台输出有一些乱码,也不是中文乱码,尝试调试编码,没有解决,有解决乱码的同学可以告知一下。
