# 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整体架构-来自网络](https://img-blog.csdnimg.cn/20210606104411293.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_1,color_FFFFFF,t_70#pic_center) ![连接器和容器-来自网络](https://img-blog.csdnimg.cn/20210606104510147.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_1,color_FFFFFF,t_70#pic_center) ## 搭建源码阅读环境 阅读学习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。 ![源码完整目录](https://img-blog.csdnimg.cn/20210606103513255.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_1,color_FFFFFF,t_70#pic_center) #### (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包警告](https://img-blog.csdnimg.cn/20210606103559864.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_1,color_FFFFFF,t_70#pic_center) - 安装包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`的初始化,不推荐这样做,一定要找到原因。) ![解决JasperInitializer不能初始化问题](https://img-blog.csdnimg.cn/20210606103636921.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_1,color_FFFFFF,t_70#pic_center) #### (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 ``` ![Edit Configurations...](https://img-blog.csdnimg.cn/20210606103744501.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_1,color_FFFFFF,t_70#pic_center) #### (4)运行并访问 完成以上三步,就可以运行了: ![运行起来了,耶](https://img-blog.csdnimg.cn/20210606103926878.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_16,color_FFFFFF,t_70#pic_center) 如果`test`目录有报错,可删除报错的位置(最好不要删除整个`test`目录,可以自己在`test`目录里写测试类`debug`)。正常运行后,在浏览器中访问http://127.0.0.1:8080/ , 点击页面中的超链接如`Documentation`、`Configuration`等都可以正常访问。 ![ROOT首页](https://img-blog.csdnimg.cn/20210606104042437.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_1,color_FFFFFF,t_70#pic_center) ![/docs/config](https://img-blog.csdnimg.cn/20210606104110685.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_1,color_FFFFFF,t_70#pic_center) #### (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 ``` ![-config start](https://img-blog.csdnimg.cn/20210606104208594.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_1,color_FFFFFF,t_70#pic_center) 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下,同时需要手动指定依赖: ![ecj-4.18](https://img-blog.csdnimg.cn/20210606104240625.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_1,color_FFFFFF,t_70#pic_center) 依赖调整好以后,其他操作都和`apache-tomcat-8.5.9-src`一样。但是运行10.0.6后控制台输出有一些乱码,也不是中文乱码,尝试调试编码,没有解决,有解决乱码的同学可以告知一下。 ![Tomcat10也运行起来了,但是有乱码。。](https://img-blog.csdnimg.cn/20210606104315304.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNjU4NjEyMA==,size_1,color_FFFFFF,t_70#pic_center)