准备工作
调试工具:
idea 2023.3.2 + maven-3.6.3 + jdk 1.8
源码获取方式:
tomcat源码地址:github.com/apache/tomc...
clone:github.com/apache/tomc...
考虑到很多国内网络环境原因,直接在gitee上新建仓库,导入即可,gitee操作如下
导入之后:
点击确定即可,这样源码就clone到gitee上了,我们在gitee上新建一个分支,以9.0.x分支为基准,建一个9.0x-study,接下来就是clone你gitee的分支,我相信大家都是clone的一把老手了,就忽略步骤了。
正式开始
接下来就开始我们的环境搭建,idea打开tomcat源码,切换到我们的目标分支上(9.0x-study)分支上,由于tomcat是用ant进行管理,我没有使用ant,我使用的是maven,原理都差不多,都是下载依赖jar包, 在tomcat目录下,新建一个pom.xml文件,这里我也是搜了一下别人的方案,有坑,经过排查之后的文件内容如下:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat</artifactId>
<name>tomcat</name>
<version>9.0</version>
<description>9.0.x分支有效,其他分支请自己尝试解决</description>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
<version>1.6.5</version>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>4.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
<dependency>
<groupId>biz.aQute.bnd</groupId>
<artifactId>biz.aQute.bndlib</artifactId>
<version>5.2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxrpc</artifactId>
<version>1.1</version>
</dependency>
<!-- 网上大多数都是下面的配置,有错误
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.6.1</version>
</dependency> -->
<!--此配置项才是正确的,上面那个包迁移了,有很多代码里配置项都找不到会报错-->
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>ecj</artifactId>
<version>3.26.0</version>
</dependency>
</dependencies>
<build>
<finalName>tomcat</finalName>
<sourceDirectory>java</sourceDirectory>
<resources>
<resource>
<directory>java</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>test</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<encoding>UTF-8</encoding>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
</plugin>
</plugins>
</build>
</project>
然后直接加载pom文件,开始下载依赖。
开始启动
首先我们需要找到tomcat的启动类,那该怎么找到呢? 回想我们启动tomcat的过程,以liunx为例,首先我们会去tomcat的bin目录下,执行startup.sh这个脚本,那么我们就顺着这个脚本往下看,一层层的去找到最后的方法,毕竟咱们java的启动入口是main方法,对吧!
在脚本里又去执行了catalina.sh,那么我们继续往下看catalina脚本,在脚本里,判断参数啥的,还有就是一些设置之类的,关键的在后,不管走什么分支,都会执行如下一行代码:
脚本具体的内容因为本人水平有限,不展开细说,主要关键的一句代码
bash
org.apache.catalina.startup.Bootstrap "$@" start
这是主启动类,我们去看看对应的源码,里面有一个main方法,重要的事情说三遍,main方法、main方法、main方法.
我们java启动的函数入口,终于追到这个方法了,看情况是执行catalina.sh的时候,脚本传了一个参数:start,对应的源码里判断args的参数是不是start,那么我们启动的时候,肯定要给main方法也传入一个start参数,这样才能对应好里面的分支条件判断,执行分支的代码吧,当然也有别的参数要传入如下参数需要传:
ini
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=F:\workspace\java\tomcat\conf\logging.properties
怎么传入进去呢? 我们需要打开idea的启动选项如下所示:
编辑配置
添加一个应用程序
解释如下: 1、选择一个jdk版本,我这里用的是8,可以看看官网对应的版本就可以,而且idea可以管理多个Jdk版本,很方便,小伙伴搜一下就可以,这里不做过多的解释 2、填写我们的参数,直接复制就可以,里面的logging.properties 路径要根据你具体tomcat路径填写要绝对路径哈 3、填写我们的启动类,直接填写 org.apache.catalina.startup.Bootstrap 就可以,复制的时候注意空格 4、填写启动的参数start。 温馨提示,有很多小伙伴更新到最新的版本之后,只有一处填写启动参数的地方,可以打开选项,打开添加虚拟机选项,就会多一行
至此可以打开debug开启你的调试之路了,可以跟上源代码流程,以下是我遇到的问题,启动乱码,直接去 org.apache.tomcat.util.res.StringManager#getString 方法里面(注意哦,有重载),关注一个参数的方法 ,在最后返回str的时候,直接转码一下,因为默认的编码是ISO-8850-1,可能在启动参数的时候,加上编码字符集也可以,不过我没加
javascript
if(str!=null){
try {
str = new String(str.getBytes("ISO-8859-1"), "UTF-8");
}catch (Exception exception){
}
}
如果解析jsp报错,可以尝试一下方法打开org.apache.catalina.startup.ContextConfig#configureStart 方法中,添加一行代码,是为了解析jsp的,默认是没有需要自己加
代码如下:
csharp
context.addServletContainerInitializer(new JasperInitializer(), null);
至此,我本地启动已经可以了,而且直接访问127.0.0.1:8080 可以直接出现tomcat的首页,如果有问题,可以一起探讨。