源码下载(Source Code Distributions)地址:https://tomcat.apache.org/download-90.cgi
tomcat 和 servlet 以及 jdk 版本的对应关系:http://tomcat.apache.org/whichversion.html
附上搭建好的环境:https://gitee.com/jhxxb/MyTomcat
Maven方式
一、解压源码
在源码根目录新建 home 文件夹,把 conf 文件夹和 webapps 文件夹移动到 home 文件夹里,然后在源码根目录新建 pom.xml 文件(原来为 Ant 工程,这里把它改为 Maven 工程)
pom.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.19</version> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.ant</groupId> <artifactId>ant</artifactId> <version>1.10.5</version> </dependency> <dependency> <groupId>wsdl4j</groupId> <artifactId>wsdl4j</artifactId> <version>1.6.3</version> </dependency> <!--<dependency>--> <!--<groupId>javax.xml</groupId>--> <!--<artifactId>jaxrpc</artifactId>--> <!--<version>1.1</version>--> <!--</dependency>--> <dependency> <groupId>org.apache.geronimo.specs</groupId> <artifactId>geronimo-jaxrpc_1.1_spec</artifactId> <version>2.1</version> </dependency> <!--<dependency>--> <!--<groupId>org.eclipse.jdt.core.compiler</groupId>--> <!--<artifactId>ecj</artifactId>--> <!--<version>4.5</version>--> <!--</dependency>--> <dependency> <groupId>org.eclipse.jdt</groupId> <artifactId>ecj</artifactId> <version>3.17.0</version> </dependency> <dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>4.0.2</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project>
二、用 IDEA 直接打开
这里删除了一些无用的文件
1.打开项目属性(F4)
把 java 文件夹标记为 Sources,test 文件夹标记为 Tests
2.运行
找到 org.apache.catalina.startup.Bootstrap 运行 main 方法
2.1、ResponseTrailers 找不到,把 homewebappsexamplesWEB-INFclasses railers 目录拷贝到 test 目录下
ResponseTrailers.java
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package trailers; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * This example writes some trailer fields to the HTTP response. */ public class ResponseTrailers extends HttpServlet { private static final long serialVersionUID = 1L; private static final Supplier<Map<String,String>> TRAILER_FIELD_SUPPLIER = new TrailerFieldSupplier(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setTrailerFields(TRAILER_FIELD_SUPPLIER); resp.setContentType("text/plain"); resp.setCharacterEncoding("UTF-8"); PrintWriter pw = resp.getWriter(); pw.print("This response should include trailer fields."); } private static class TrailerFieldSupplier implements Supplier<Map<String,String>> { private static final Map<String,String> trailerFields = new HashMap<>(); static { trailerFields.put("x-trailer-1", "Trailer value one"); trailerFields.put("x-trailer-2", "Trailer value two"); } @Override public Map<String, String> get() { return trailerFields; } } }
2.2、CookieFilter 找不到,把 homewebappsexamplesWEB-INFclassesutilCookieFilter.java 文件拷贝到 testutil 目录下
CookieFilter.java
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package util; import java.util.Locale; import java.util.StringTokenizer; /** * Processes a cookie header and attempts to obfuscate any cookie values that * represent session IDs from other web applications. Since session cookie names * are configurable, as are session ID lengths, this filter is not expected to * be 100% effective. * * It is required that the examples web application is removed in security * conscious environments as documented in the Security How-To. This filter is * intended to reduce the impact of failing to follow that advice. A failure by * this filter to obfuscate a session ID or similar value is not a security * vulnerability. In such instances the vulnerability is the failure to remove * the examples web application. */ public class CookieFilter { private static final String OBFUSCATED = "[obfuscated]"; private CookieFilter() { // Hide default constructor } public static String filter(String cookieHeader, String sessionId) { StringBuilder sb = new StringBuilder(cookieHeader.length()); // Cookie name value pairs are ';' separated. // Session IDs don't use ; in the value so don't worry about quoted // values that contain ; StringTokenizer st = new StringTokenizer(cookieHeader, ";"); boolean first = true; while (st.hasMoreTokens()) { if (first) { first = false; } else { sb.append(';'); } sb.append(filterNameValuePair(st.nextToken(), sessionId)); } return sb.toString(); } private static String filterNameValuePair(String input, String sessionId) { int i = input.indexOf('='); if (i == -1) { return input; } String name = input.substring(0, i); String value = input.substring(i + 1, input.length()); return name + "=" + filter(name, value, sessionId); } public static String filter(String cookieName, String cookieValue, String sessionId) { if (cookieName.toLowerCase(Locale.ENGLISH).contains("jsessionid") && (sessionId == null || !cookieValue.contains(sessionId))) { cookieValue = OBFUSCATED; } return cookieValue; } }
2.3、confserver.xml 找不到,设置下 jvm 参数(就是指定之前创建的 home 目录)
-Dcatalina.home=D:CodeLib omcat9home
2.4、控制台报错:Error configuring application listener of class [listeners.ContextListener]
没找到具体原因,删掉 webapps 下的 examples 文件夹即可
或者下载正常 tomcat 版本,也就是非源码版本,把其中的 examples 替换进来
2.5、控制台或网页报错:Servlet.service() for servlet [jsp] in context with path [] threw exception [org.apache.jasper.JasperException: Unable to compile class for JSP] with root cause
编辑 org.apache.catalina.startup.ContextConfig 文件的 configureStart() 方法,添加初始化 JSP 解析器的代码
context.addServletContainerInitializer(new JasperInitializer(), null);
最后访问 http://127.0.0.1:8080/ 就可以看到欢迎页了
Ant方式
解压 tomcat 源码,编辑 build.properties.default 文件,修改 base.path 路径
# ----- Default Base Path for Dependent Packages ----- # Please note this path must be absolute, not relative, # as it is referenced with different working directory # contexts by the various build scripts. base.path=D:/CodeLib/apache-tomcat-9.0.19-src/tomcat-build-libs
下载 Ant,配置环境变量
https://ant.apache.org/bindownload.cgi
# 设置系统环境变量 setx /M ANT_HOME "D:apache-ant-1.10.5" setx /M Path "%Path%;%ANT_HOME%in"
编译 tomcat,生成 idea 项目
cd D:CodeLibapache-tomcat-9.0.19-src
ant
ant ide-intellij
用 idea 打开源码目录,会提示设置变量属性,按照自己设置的目录设置即可,后面运行和 Maven 方式类似