tomcat 学习记录
- tomcat 编译
- ant 下载
- 编译
- 运行
- 源码Debug
- 运行 Bootstrap
- 运行Tomcat
- 查看状态
- pom.xml
- 测试
- EmbeddedTomcat
- 参考
- 书籍
- 博客
tomcat 编译
下载 tomcat 10 源码,解压然后idea导入
包存放的默认位置如下:base.path=${user.home}/tomcat-build-libs
同时在项目的 tomcat/res/ide-support/idea/tomcat.iml
文件中提供了jar的依赖配置方式, 可以覆盖 .idea
配置,但对于 社区版有些插件是无法安装的,就从 ${user.home}/tomcat-build-libs
手动导入 jar 包
参考
- Tomcat 源码阅读与调试环境搭建 - 基于Idea和Tomcat 8.5
ant 下载
ant 二进制包下载 后添加环境变量 %ANT_HOME%\bin
,idea2023 会自动识别, 或者打开 help-> action 搜索 ant
编译
- 根路径下
build.properties.default
,将其复制为build.properties
- 打开
ant
侧边栏,点击“+”,选择tomcat下的build.xml文件 - 由于 windows默认编码集为GBK,由于使用startup.bat启动tomcat时,它会读取catalina.bat的代码并打开一个新窗口运行。打开的cmd默认编码可能不是utf-8,与系统编码不一致,所以导致乱码
- 通过修改注册表
- 修改 conf/logging.properties 日志编码为GBK
- 在项目结构设置里,添加 JDK,同时设置 java 目录为源代码目录
点击 ant 窗口的运行按钮
运行
在输出目录下的 build/bin
运行 startup.bat
在浏览器 http://localhost:8080/
源码Debug
导入 ant 依赖
导入 ${user.home}/tomcat-build-libs
下的依赖
针对 java lang ClassNotFoundException listeners ContextListener
错误,是由于在idea的maven项目中要将java文件编译,加载进内存需要将文件夹设置为Sources Root
运行 Bootstrap
在 java/org/apache/catalina/startup/Bootstrap.java
中,自己调试运行
运行Tomcat
代码路径 java/org/apache/catalina/startup/Tomcat.java
public static void main(String[] args) throws Exception {// Process some command line parametersString[] catalinaArguments = null;for (int i = 0; i < args.length; i++) {if (args[i].equals("--no-jmx")) {Registry.disableRegistry();} else if (args[i].equals("--catalina")) {// This was already processed before// Skip the rest of the arguments as they are for CatalinaArrayList<String> result = new ArrayList<>();for (int j = i + 1; j < args.length; j++) {result.add(args[j]);}catalinaArguments = result.toArray(new String[0]);break;}}SecurityClassLoad.securityClassLoad(Thread.currentThread().getContextClassLoader());Tomcat tomcat = new Tomcat();// Create a Catalina instance and let it parse the configuration files// It will also set a shutdown hook to stop the Server when needed// Use the default configuration sourcetomcat.init(null, catalinaArguments);boolean await = false;String path = "";// Process command line parametersfor (int i = 0; i < args.length; i++) {if (args[i].equals("--war")) {if (++i >= args.length) {throw new IllegalArgumentException(sm.getString("tomcat.invalidCommandLine", args[i - 1]));}File war = new File(args[i]);tomcat.addWebapp(path, war.getAbsolutePath());} else if (args[i].equals("--path")) {if (++i >= args.length) {throw new IllegalArgumentException(sm.getString("tomcat.invalidCommandLine", args[i - 1]));}path = args[i];} else if (args[i].equals("--await")) {await = true;} else if (args[i].equals("--no-jmx")) {// This was already processed before} else if (args[i].equals("--catalina")) {// This was already processed before// Skip the rest of the arguments as they are for Catalinabreak;} else {throw new IllegalArgumentException(sm.getString("tomcat.invalidCommandLine", args[i]));}}tomcat.start();// Ideally the utility threads are non daemonif (await) {tomcat.getServer().await();}
}
查看状态
在 conf/tomcat-users.xml
添加用户
<user username="admin" password="admin" roles="manager-gui,admin-gui,tomcat"/>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--~ 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.--><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-10.1.16-src</artifactId><name>Tomcat</name><version>10.1.16</version><build><!--指定源目录--><finalName>apache-tomcat-10.1.16-src</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>11</source><target>11</target></configuration></plugin></plugins></build><!--tomcat 依赖的基础包--><dependencies><dependency><groupId>geronimo-spec</groupId><artifactId>geronimo-spec-jaxrpc</artifactId><version>1.1-rc4</version></dependency><dependency><groupId>wsdl4j</groupId><artifactId>wsdl4j</artifactId><version>1.6.3</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><dependency><groupId>org.hamcrest</groupId><artifactId>hamcrest</artifactId><version>2.2</version><scope>test</scope></dependency><dependency><groupId>org.easymock</groupId><artifactId>easymock</artifactId><version>4.3</version></dependency><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version></dependency><dependency><groupId>org.objenesis</groupId><artifactId>objenesis</artifactId><version>3.3</version></dependency><dependency><groupId>com.unboundid</groupId><artifactId>unboundid-ldapsdk</artifactId><version>6.0.10</version></dependency><dependency><groupId>com.puppycrawl.tools</groupId><artifactId>checkstyle</artifactId><version>10.12.4</version></dependency><dependency><groupId>org.jacoco</groupId><artifactId>org.jacoco.agent</artifactId><version>0.8.11</version></dependency><dependency><groupId>com.github.spotbugs</groupId><artifactId>spotbugs</artifactId><version>4.8.0</version><type>pom</type></dependency><dependency><groupId>biz.aQute.bnd</groupId><artifactId>biz.aQute.bndlib</artifactId><version>7.0.0</version></dependency><dependency><groupId>org.apache.tomcat</groupId><artifactId>jakartaee-migration</artifactId><version>1.0.7</version></dependency><dependency><groupId>net.jsign</groupId><artifactId>jsign-core</artifactId><version>5.0</version></dependency><dependency><groupId>org.apache.derby</groupId><artifactId>derby</artifactId><version>10.16.1.1</version><scope>test</scope></dependency><dependency><groupId>ant</groupId><artifactId>ant</artifactId><version>1.7.0</version></dependency><dependency><groupId>org.eclipse.jdt</groupId><artifactId>ecj</artifactId><version>3.36.0</version></dependency><dependency><groupId>org.apache.tomcat</groupId><artifactId>tomcat-juli</artifactId><version>11.0.0-M14</version></dependency></dependencies>
</project>
测试
EmbeddedTomcat
public class EmbeddedTomcat {private static void resetLogging() {final String loggingConfig = "handlers = java.util.logging.ConsoleHandler\n" +".handlers = java.util.logging.ConsoleHandler\n" +"java.util.logging.ConsoleHandler.level = FINE\n" +"java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter\n" +"java.util.logging.ConsoleHandler.encoding = UTF-8\n";try {InputStream is = new ByteArrayInputStream(loggingConfig.getBytes(StandardCharsets.UTF_8));LogManager.getLogManager().readConfiguration(is);LogFactory.getLog(EmbeddedTomcat.class).info("Logger configured to System.out");} catch (SecurityException | IOException e) {// Ignore, the VM default will be used}}public static void main(String... args) throws Exception {Registry.disableRegistry();Tomcat tomcat = new Tomcat();resetLogging();tomcat.setPort(8080);Connector connector = tomcat.getConnector();connector.setProperty("bindOnInit", "false");// No file system docBase requiredContext ctx = tomcat.addContext("", null);skipTldsForResourceJars(ctx);CounterServlet counterServlet = new CounterServlet();Tomcat.addServlet(ctx, "counterServlet", counterServlet);ctx.addServletMappingDecoded("/", "counterServlet");//ctx.addApplicationListener(new WsContextListener());tomcat.start();Thread.sleep(60*1000);}public static void skipTldsForResourceJars(Context context) {StandardJarScanner scanner = (StandardJarScanner) context.getJarScanner();StandardJarScanFilter filter = (StandardJarScanFilter) scanner.getJarScanFilter();filter.setTldSkip(filter.getTldSkip() + ",resources*.jar");}private static class CounterServlet extends HttpServlet {private static final long serialVersionUID = 1L;private AtomicInteger callCount = new AtomicInteger(0);@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {req.getSession(true);resp.setContentType("text/plain");resp.getWriter().print("OK: " + req.getRequestURL() + "[" + callCount.incrementAndGet()+ "]");}}
}
参考
- Apache Tomcat
书籍
- 深入剖析 Tomcat
- Tomcat 架构解析
博客
- Tomcat源码详解知识体系详解
- tomcat源码分析
- Tomcat 分析