前言
最近开始研究下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.0http://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.deployDirectory26-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 oneif (ok) {authenticatorConfig();}// Dump the contents of this pipeline if requestedif (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 encounteredif (ok) {context.setConfigured(true);} else {log.error(sm.getString("contextConfig.unavailable"));context.setConfigured(false);}}
再启动访问就完美了
