前言
最近开始研究下Tomcat源码,毕竟用了这么多年了,却没有深入了解它,最多网上看看博文帖子,知道它由什么Server、Service、Engine、Host、Context、Wrapper等组件,却完全不知道,真正的数据流动,比如怎么解析浏览器请求,怎么到Servlet的,所以考虑搭建下源码环境,仔细debug下。
下载源码
这个只需要访问官网
https://tomcat.apache.org/
然后点击左边的Download,这里下载的是Tomcat8,版本为8.5.75,进入到Tomcat8的页面https://tomcat.apache.org/download-80.cgi
点击最下面的Source Code Distributions-zip,具体链接为
https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.75/src/apache-tomcat-8.5.75-src.zip
还有eclipse,jdk,maven等这些必备的工具环境,话说网上有人说应为tomcat是用ant构建的,所以也要下载ant,然后进入源码目录里面cmd执行ant,可惜我这里不知怎么回事,一直报如下错误,可能是网络不行。
所以还是采取maven的方式
导入源码
我们在源码目录里面新建pom.xml文件,内如如下(改为自己的tomcat版本)
<?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>apache-tomcat-8.5.75-src</artifactId>
<name>Tomcat8.5.75</name>
<version>8.5.75</version>
<build>
<!--指定源⽬录 -->
<finalName>Tomcat8.5.75</finalName>
<sourceDirectory>java</sourceDirectory>
<resources>
<resource>
<directory>java</directory>
</resource>
</resources>
<plugins>
<!--引⼊编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<encoding>UTF-8</encoding>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<!--tomcat 依赖的基础包 -->
<dependencies>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
<version>1.7.0</version>
</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.5.1</version>
</dependency>
<dependency>
<groupId>javax.xml.soap</groupId>
<artifactId>javax.xml.soap-api</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
</project>
然后用eclipse导入已存在的maven项目就可以了
启动测试
Tomcat的启动类是org.apache.catalina.startup.Bootstrap,只有这个类有个main方法,右键配置Debug Configurations,配置Arguments下面的VM arguments添加如下配置
-Dcatalina.home=F:/Source/apache-tomcat-8.5.75-src
-Dcatalina.base=F:/Source/apache-tomcat-8.5.75-src
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=F:/Source/apache-tomcat-8.5.75-src/conf/logging.properties
然后右键debug启动,发现启动成功
26-Feb-2022 15:07:02.364 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory
26-Feb-2022 15:07:02.442 信息 [main] org.apache.catalina.startup.Catalina.start Server startup in 2810 ms
浏览器访问http://localhost:8080/,发现乱码了
看错误是JSP解析引擎未初始化,我们去org.apache.catalina.startup.ContextConfig的configureStart方法webConfig();后面加上
//初始化JSP解析引擎
context.addServletContainerInitializer(new JasperInitializer(),null);
protected synchronized void configureStart() {
// Called from StandardContext.start()
if (log.isDebugEnabled()) {
log.debug(sm.getString("contextConfig.start"));
}
if (log.isDebugEnabled()) {
log.debug(sm.getString("contextConfig.xmlSettings",
context.getName(),
Boolean.valueOf(context.getXmlValidation()),
Boolean.valueOf(context.getXmlNamespaceAware())));
}
webConfig();
//初始化JSP解析引擎
context.addServletContainerInitializer(new JasperInitializer(),null);
if (!context.getIgnoreAnnotations()) {
applicationAnnotationsConfig();
}
if (ok) {
validateSecurityRoles();
}
// Configure an authenticator if we need one
if (ok) {
authenticatorConfig();
}
// Dump the contents of this pipeline if requested
if (log.isDebugEnabled()) {
log.debug("Pipeline Configuration:");
Pipeline pipeline = context.getPipeline();
Valve valves[] = null;
if (pipeline != null) {
valves = pipeline.getValves();
}
if (valves != null) {
for (Valve valve : valves) {
log.debug(" " + valve.getClass().getName());
}
}
log.debug("======================");
}
// Make our application available if no problems were encountered
if (ok) {
context.setConfigured(true);
} else {
log.error(sm.getString("contextConfig.unavailable"));
context.setConfigured(false);
}
}
再启动访问就完美了