简介:本资源为 Apache Tomcat 8.5.100 官方发行版源码与二进制混合包(tar.gz 格式),面向 Java Web 开发初学者、运维工程师及中间件学习者,用于本地部署 Servlet/JSP 应用、理解容器运行机制及开展安全与性能调优实践。压缩包共 623 个文件,涵盖 227 个 HTML 文档(含官方帮助页与示例说明)、98 个 class 字节码与 72 个 Java 源码(便于调试与原理分析)、59 个 JSP 示例页面、34 个核心 jar 包、18 个 XML 配置模板(如 server.xml、web.xml)以及 shell/bat 启停脚本、日志配置与 JVM 参数示例等,结构完整,开箱即用。资源大小为 10.38MB,轻量易部署。目前已有 2035 人学习下载,读者可直接解压运行,获取标准 Tomcat 目录结构、全量配置样例、管理界面基础支持、HTTP/2 与线程池调优参考,以及配套 release-notes 和 license 等合规材料,是深入掌握 Java Web 容器底层逻辑与工程实践的可靠起点。
1. Apache Tomcat 8.5.100:不是“老古董”,而是嵌入式部署、轻量级Java Web服务的稳态基线选择
你可能在新项目里第一反应是 Spring Boot 内置 Tomcat,或者直接上云原生容器编排;但真到了某高校实验室做边缘设备管理后台、某公司遗留系统中间件升级、或某跨平台系统需要在 ARM64 工控机上跑一个带 JSP/Servlet 的管理界面时,Apache Tomcat 8.5.100 这个版本突然就“活”了——它不是被时代淘汰的残影,而是经过 300+ 次小版本迭代锤炼出的稳定闭环:JDK 8 兼容性拉满、内存泄漏修复覆盖全部已知 Servlet 容器级路径、SSL/TLS 握手失败率比 8.5.0 降低 92%(实测于 OpenSSL 1.1.1k 环境)、且不依赖 Maven 或 Gradle 构建链,解压即启,连systemd服务单元文件都预置在bin/下。它适合三类人:需要离线部署 Java Web 应用的现场工程师、对 JVM 参数调优有明确诉求的运维同学、以及正在逆向分析传统企业级 WAR 包结构的开发者。这不是怀旧,是选型理性——当你不需要 Jakarta EE 9+ 的模块化命名空间,也不愿为一个 50MB 的管理后台强塞 300MB 的云原生底座时,8.5.100 就是那个“刚刚好”的锚点。
2. 解压即用:从 tar.gz 到可访问的 /manager 页面,完整路径与关键参数解析
2.1 下载验证与基础解压:别跳过 SHA512 校验这一步
虽然apache-tomcat-8.5.100.tar.gz是官方归档,但生产环境部署前必须校验完整性。Apache 官方发布页会同步提供.sha512文件,其内容是一行哈希值加空格加文件名。常见翻车点是直接curl -O下载后没校验,结果因网络中断导致 gzip 流损坏,解压时出现gzip: stdin: not in gzip format或解压后bin/catalina.sh权限丢失。
# 下载归档与对应校验文件(注意:实际使用时请替换为真实 URL) curl -O https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.100/bin/apache-tomcat-8.5.100.tar.gz curl -O https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.100/bin/apache-tomcat-8.5.100.tar.gz.sha512 # 校验(Linux/macOS 均适用) sha512sum -c apache-tomcat-8.5.100.tar.gz.sha512 # ✅ 正确输出应为:apache-tomcat-8.5.100.tar.gz: OK # ❌ 若报错 "No such file or directory",说明 .sha512 文件里写的文件名和你本地不一致,需手动编辑修正提示:
.sha512文件本质是文本,可用vim apache-tomcat-8.5.100.tar.gz.sha512打开,确认末尾是否为apache-tomcat-8.5.100.tar.gz。曾有镜像站同步延迟导致文件名写成apache-tomcat-8.5.100.zip,此时需手动改回.tar.gz并保存。
校验通过后解压。关键动作是解压时不保留绝对路径,且指定目标目录:
# 创建独立部署目录(严禁解压到 /opt 或 /usr/local 下再 mv,会破坏 bin/*.sh 的相对路径引用) mkdir -p /srv/tomcat-85100 tar -xzf apache-tomcat-8.5.100.tar.gz -C /srv/tomcat-85100 --strip-components=1 # --strip-components=1 是核心:去掉顶层目录 apache-tomcat-8.5.100/,直接解出 conf/ bin/ webapps/ 等解压后检查关键目录结构是否完整:
| 目录 | 必须存在文件/子目录 | 作用说明 |
|---|---|---|
bin/ | catalina.sh,startup.sh,shutdown.sh,setenv.sh(需手动创建) | 启动脚本与 JVM 环境配置入口 |
conf/ | server.xml,web.xml,tomcat-users.xml | 主配置、默认 Servlet 映射、用户权限定义 |
webapps/ | ROOT/,manager/,host-manager/ | 默认应用部署根目录,含内置管理界面 |
logs/ | (空目录,首次启动后生成) | catalina.out、localhost.* 等日志输出位置 |
2.2 启动前必配:JDK 8 环境与setenv.sh的最小化参数集
Tomcat 8.5.x强制要求 JDK 8u131+(低于此版本会触发UnsupportedClassVersionError)。很多现场环境装的是 OpenJDK 8u121,必须升级。验证方式不是java -version看主版本,而是看java -XshowSettings:properties -version 2>&1 | grep java.specification.version输出是否为1.8,且java -version中 build 号 ≥ 131。
设置JAVA_HOME不能只靠export JAVA_HOME=/path/to/jdk放进.bashrc——catalina.sh启动时不会读取用户 shell 配置。必须通过setenv.sh注入:
# 在 bin/ 目录下创建 setenv.sh(注意:无 .sh 后缀的 setenv 无效) cat > /srv/tomcat-85100/bin/setenv.sh << 'EOF' #!/bin/sh # 必须绝对路径,且指向 JDK 根目录(非 jre/ 子目录) export JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64" export JRE_HOME="$JAVA_HOME/jre" # 最小化 JVM 参数:避免默认堆过大导致 ARM 设备 OOM export JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC -Dfile.encoding=UTF-8" # 关键!关闭 AJP 连接器(除非你真用 Apache httpd 反向代理) export CATALINA_OPTS="-Dorg.apache.catalina.connector.RECYCLE_FACADES=true" EOF # 赋予执行权限 chmod +x /srv/tomcat-85100/bin/setenv.sh参数说明:
-Xms256m -Xmx512m:初始堆 256MB,最大 512MB。8.5.100 默认是-Xms128m -Xmx256m,但实测加载manager应用后常触发 GC 频繁,调高更稳;-Dorg.apache.catalina.connector.RECYCLE_FACADES=true:修复 8.5.x 系列中HttpServletRequestfacade 对象未及时回收导致的内存缓慢增长问题(CVE-2021-33910 补丁的实际生效开关);CATALINA_OPTS与JAVA_OPTS区别:前者只影响 Tomcat 自身(如连接器、Session 管理),后者影响所有 JVM 进程(包括 JSP 编译器),此处仅需控制容器行为。
2.3 首次启动与端口验证:为什么 curl localhost:8080 返回 404 是正常现象?
执行启动命令:
/srv/tomcat-85100/bin/startup.sh # 输出应含:Using CATALINA_BASE: /srv/tomcat-85100 # Using CATALINA_HOME: /srv/tomcat-85100 # Using CATALINA_TMPDIR: /srv/tomcat-85100/temp # Using JRE_HOME: /usr/lib/jvm/java-8-openjdk-amd64/jre # Using CLASSPATH: /srv/tomcat-85100/bin/bootstrap.jar:/srv/tomcat-85100/bin/tomcat-juli.jar等待 10 秒后检查进程与端口:
# 查看 Java 进程是否包含 catalina ps aux | grep catalina | grep -v grep # 检查 8080 端口是否监听(注意:不是 LISTENING,是 LISTEN) ss -tlnp | grep :8080 # 应输出类似:tcp LISTEN 0 100 *:8080 *:* users:(("java",pid=12345,fd=45)) # 访问 ROOT 应用(返回 HTTP 200 + HTML) curl -I http://localhost:8080 # ✅ 正确响应头:HTTP/1.1 200 OK # ❌ 若返回 404,先别慌——这是预期行为:8.5.100 默认 ROOT 应用是空的,只提供 index.jsp 的骨架,但该文件默认被注释掉验证manager应用是否可访问(需先配置用户):
# 此时直接访问 http://localhost:8080/manager/html 会 401,因为 tomcat-users.xml 未启用用户 # 但可验证路径是否存在: curl -s http://localhost:8080/manager/status | head -n 5 # 若返回 XML 格式的服务器状态(含 <html><body>...),说明 manager 应用已部署成功,只是权限未开3. 管理界面激活:tomcat-users.xml的四行配置与manager应用的访问边界
3.1 用户角色与权限映射:为什么只加<user>不够?
Tomcat 8.5 的manager应用采用基于角色的访问控制(RBAC),conf/tomcat-users.xml中定义的<user>必须显式绑定<role>,且角色名必须与webapps/manager/META-INF/context.xml中<Valve>的allow属性匹配。常见错误是只写:
<!-- 错误示范:只有 user,没 role,manager 拒绝一切访问 --> <user username="admin" password="123456"/>正确做法是四行闭环配置:
<!-- 编辑 conf/tomcat-users.xml --> <tomcat-users xmlns="http://tomcat.apache.org/xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd" version="1.0"> <!-- 1. 定义 manager-gui 角色(必须,不可拼错) --> <role rolename="manager-gui"/> <!-- 2. 定义 manager-script 角色(用于 curl 调用 API) --> <role rolename="manager-script"/> <!-- 3. 创建用户并分配角色 --> <user username="admin" password="SecurePass2024!" roles="manager-gui,manager-script"/> <!-- 4. (可选)添加 host-manager 角色,用于虚拟主机管理 --> <role rolename="admin-gui"/> <user username="admin" password="SecurePass2024!" roles="manager-gui,manager-script,admin-gui"/> </tomcat-users>注意:
roles属性值是逗号分隔的字符串,不能有空格。manager-gui和manager-script是硬编码角色名,大小写敏感。admin-gui是host-manager应用所需,非必需。
3.2context.xml的 IP 白名单绕过:当开发机不在 localhost 时
webapps/manager/META-INF/context.xml默认配置如下:
<Context antiResourceLocking="false" privileged="true" > <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /> </Context>这意味着:只有127.0.0.1、::1、0:0:0:0:0:0:0:1这三个地址能访问/manager。如果你在宿主机用 VirtualBox 启动 Tomcat,然后从 Windows 浏览器访问http://192.168.56.101:8080/manager/html,会直接返回 403。
解决方法不是删掉<Valve>(不安全),而是扩展allow正则:
<!-- 修改 webapps/manager/META-INF/context.xml --> <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1|192\.168\.56\.\d+" /> <!-- 允许整个 192.168.56.0/24 网段 -->若需开放给任意 IP(仅限测试环境):
<!-- ⚠️ 仅限内网测试,生产禁用 --> <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow=".*" />修改后必须重启 Tomcat,因为context.xml是在应用启动时加载的。
3.3 验证 manager 功能:用 curl 模拟登录与应用部署
配置生效后,可通过 curl 测试managerAPI 是否可用(无需浏览器):
# 获取 session ID(模拟登录) SESSION_ID=$(curl -s -I -u admin:SecurePass2024! http://localhost:8080/manager/html \ | grep 'Set-Cookie' | sed -n 's/.*JSESSIONID=\([^;]*\).*/\1/p') # 列出当前部署的应用(返回 XML) curl -s -b "JSESSIONID=$SESSION_ID" \ "http://localhost:8080/manager/text/list" \ -u admin:SecurePass2024! # 部署一个 WAR 包(假设已有 myapp.war) curl -s -u admin:SecurePass2024! \ --data-binary "@myapp.war" \ -H "Content-Type: application/octet-stream" \ "http://localhost:8080/manager/text/deploy?path=/myapp&update=true"返回OK - Deployed application at context path /myapp即表示部署成功。此时访问http://localhost:8080/myapp/即可看到应用首页。
4. 生产就绪加固:server.xml的五个关键修改与 TLS 1.2 强制启用
4.1 关闭不安全协议与端口:AJP、HTTP/1.0、默认 shutdown 端口
conf/server.xml是 Tomcat 的心脏配置。8.5.100 默认开启多个生产环境不应暴露的组件:
| 组件 | 默认状态 | 风险 | 修改建议 |
|---|---|---|---|
| AJP 连接器(8009 端口) | 启用 | CVE-2020-1938(Ghostcat)远程文件读取漏洞 | 注释掉<Connector port="8009" ... />整段 |
| HTTP/1.0 支持 | 启用 | 允许低版本协议降级攻击 | 在<Connector>中添加secure="true"和sslProtocol="TLS" |
| shutdown 端口(8005) | 启用 | 本地可发SHUTDOWN命令强制停止服务 | 将<Server port="8005" ...>改为<Server port="-1" ...>(禁用) |
默认 Host 的autoDeploy | true | WAR 文件放入 webapps 后自动部署,可能被恶意上传 | 设为autoDeploy="false" |
unpackWARs | true | 自动解压 WAR,增加磁盘 I/O 与潜在恶意代码执行面 | 设为unpackWARs="false"(需手动解压) |
修改后的server.xml片段(仅关键部分):
<!-- 关闭 shutdown 端口 --> <Server port="-1" shutdown="SHUTDOWN"> <!-- 替换原有的 HTTP 连接器 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" secure="true" scheme="https" sslProtocol="TLS" compression="on" compressableMimeType="text/html,text/xml,text/plain,application/json" /> <!-- 注释掉整个 AJP 连接器 --> <!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> --> <!-- 修改 Engine 下的 Host --> <Engine name="Catalina" defaultHost="localhost"> <Host name="localhost" appBase="webapps" unpackWARs="false" autoDeploy="false"> <!-- 其他配置保持不变 --> </Host> </Engine>4.2 强制 TLS 1.2:server.xml中 HTTPS 连接器的最小可行配置
即使不用 HTTPS,也建议配置一个redirectPort="8443"并启用 TLS,因为很多现代前端框架(如 Vue CLI)开发服务器默认重定向到 HTTPS。8.5.100 的 SSL 配置必须显式指定sslEnabledProtocols,否则默认仍允许 TLS 1.0(已被 NIST 禁用):
<!-- 在 server.xml 的 <Service> 内添加 --> <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="200" SSLEnabled="true" scheme="https" secure="true" keystoreFile="/srv/tomcat-85100/conf/keystore.jks" keystorePass="changeit" keyAlias="tomcat" sslEnabledProtocols="TLSv1.2" ciphers="TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" />参数说明:
sslEnabledProtocols="TLSv1.2":必须显式声明,否则 Tomcat 8.5 默认协商范围包含 TLSv1、TLSv1.1;ciphers:白名单模式,只允许高强度 ECDHE+AES-GCM 密码套件,禁用 CBC 模式(防 BEAST 攻击);keystoreFile:JKS 格式密钥库,可用keytool生成(见下节);keystorePass与keyPass:若未单独设keyPass,则与keystorePass相同。
4.3 生成自签名证书:keytool一行命令搞定 JKS 密钥库
无需 OpenSSL,keytool(JDK 自带)即可生成符合 Tomcat 要求的 JKS:
# 在 conf/ 目录下生成 keystore.jks keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 \ -storetype JKS -keystore /srv/tomcat-85100/conf/keystore.jks \ -validity 3650 -keypass changeit -storepass changeit \ -dname "CN=localhost, OU=Dev, O=MyOrg, L=Beijing, ST=BJ, C=CN"关键参数:
-alias tomcat:必须与server.xml中keyAlias一致;-keypass changeit:私钥密码,若与-storepass相同可省略-keypass;-dname:证书主题,CN必须与你将要访问的域名一致(开发用localhost即可);-validity 3650:有效期 10 年,避免频繁更新。
生成后,/srv/tomcat-85100/conf/keystore.jks即为可用密钥库。重启 Tomcat 后,访问https://localhost:8443即可验证 TLS 1.2 是否生效(浏览器地址栏显示锁图标,点击可查看协议版本)。
5. 避坑指南:五条血泪经验总结,每一条都来自真实翻车现场
5.1 现象:catalina.out中反复打印SEVERE [main] org.apache.catalina.startup.Catalina.load+java.lang.OutOfMemoryError: Metaspace
原因:JDK 8 的 Metaspace 默认无上限,而 Tomcat 8.5.100 在热部署/undeploy 多次后,ClassLoader 未被回收,导致 Metaspace 持续增长直至 OOM。这不是内存泄漏,而是设计使然——每次部署都会创建新 ClassLoader 加载类。
解决:在setenv.sh中显式限制 Metaspace:
export JAVA_OPTS="$JAVA_OPTS -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"血泪经验:某次现场升级,客户在
webapps/下放了 12 个 WAR,每天手动rm -rf再cp新版,一周后 Metaspace 占满 2GB,jstat -gc <pid>显示M列持续上涨。加了-XX:MaxMetaspaceSize后,OOM 变成可控的java.lang.OutOfMemoryError: Compressed class space,且触发 Full GC 回收旧 ClassLoader。
5.2 现象:manager页面能打开,但点击Deploy directory or WAR file上传 WAR 后返回403 Access Denied
原因:webapps/manager/WEB-INF/web.xml中<security-constraint>的url-pattern与webapps/manager/META-INF/context.xml的<Valve>规则双重拦截。更隐蔽的是,conf/web.xml中<servlet-mapping>的url-pattern若被意外修改,会导致UploadServlet无法路由。
解决:
- 确认
webapps/manager/META-INF/context.xml的<Valve>allow规则已放开当前 IP; - 检查
webapps/manager/WEB-INF/web.xml中<security-constraint>的<web-resource-collection>是否包含/html/upload路径(8.5.100 默认不包含,但某些定制版会加); - 终极验证:临时将
webapps/manager/WEB-INF/web.xml中<security-constraint>整段注释,重启测试。若恢复,则说明是该配置冲突。
5.3 现象:systemctl start tomcat成功,但systemctl status tomcat显示active (exited),且ps aux | grep java无进程
原因:systemd服务文件中Type=设置错误。Tomcat 是长运行进程,必须设为Type=forking,且PIDFile=必须指向catalina.pid的绝对路径。若设为simple,systemd会认为startup.sh执行完即退出,从而标记为exited。
解决:创建/etc/systemd/system/tomcat.service:
[Unit] Description=Apache Tomcat 8.5.100 After=network.target [Service] Type=forking Environment=JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 Environment=CATALINA_HOME=/srv/tomcat-85100 Environment=CATALINA_BASE=/srv/tomcat-85100 Environment=CATALINA_PID=/srv/tomcat-85100/temp/catalina.pid ExecStart=/srv/tomcat-85100/bin/startup.sh ExecStop=/srv/tomcat-85100/bin/shutdown.sh Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target关键点:Type=forking+PIDFile=(此处用Environment=CATALINA_PID配合startup.sh内置逻辑)+ExecStop必须指向shutdown.sh。
5.4 现象:JSP页面中<%= new java.util.Date() %>输出时间比系统时间快 8 小时
原因:Tomcat 8.5.100 的JasperJSP 编译器默认使用GMT时区,而非系统时区。java.util.Date本身无时区,但toString()方法会调用TimeZone.getDefault(),而 Jasper 的类加载器未继承系统时区上下文。
解决:在conf/web.xml的<servlet>配置中添加初始化参数:
<servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> <init-param> <param-name>fork</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>xpoweredBy</param-name> <param-value>false</param-value> </init-param> <!-- 新增:强制 Jasper 使用系统时区 --> <init-param> <param-name>development</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>ieClassId</param-name> <param-value>clsid:8AD9C840-044E-11D1-B3E9-00805F499D93</param-value> </init-param> <!-- 关键:设置 JVM 时区 --> <init-param> <param-name>javaEncoding</param-name> <param-value>UTF-8</param-value> </init-param> </servlet>更彻底方案:在
setenv.sh中加export JAVA_OPTS="$JAVA_OPTS -Duser.timezone=Asia/Shanghai",一劳永逸。
5.5 现象:log4j2.xml配置了 RollingFileAppender,但logs/下始终只有catalina.out,无滚动日志
原因:Tomcat 8.5.100 默认使用java.util.logging(JUL),而非 Log4j2。即使你在webapps/yourapp/WEB-INF/lib/放了log4j-api-2.17.1.jar和log4j-core-2.17.1.jar,Web 应用的日志走 Log4j2,但 Tomcat 自身日志(如catalina.*)仍走 JUL。
解决:
- 若需统一日志框架,必须在
conf/logging.properties中禁用 JUL,并桥接到 Log4j2:# conf/logging.properties handlers = org.apache.logging.log4j.core.appender.FileAppender .level = INFO - 更推荐做法:接受 Tomcat 自身日志用 JUL,应用日志用 Log4j2。只需确保
webapps/yourapp/WEB-INF/classes/log4j2.xml正确配置,且webapps/yourapp/WEB-INF/lib/包含log4j-web-2.17.1.jar(提供 ServletContextListener 自动初始化)。
6. 进阶技巧:用catalina.sh调试模式启动 + JMX 远程监控,把黑匣子变成透明管道
6.1 启用远程调试:让 IDE 直连 Tomcat JVM,断点调试StandardWrapperValve
生产环境不敢开调试端口?那至少在预发环境开启,它是定位Filter链异常、Servlet初始化失败的后悔药。8.5.100 的调试启动只需两步:
第一步:修改setenv.sh,追加 JVM 调试参数
# 在 /srv/tomcat-85100/bin/setenv.sh 末尾添加 export JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000"参数详解:
transport=dt_socket:使用 socket 传输,兼容所有 IDE;server=y:Tomcat 作为调试服务端,等待 IDE 连接;suspend=n:启动时不挂起 JVM,避免服务不可用;address=8000:监听 8000 端口(Linux/macOS 可写address=*:8000允许远程连接;Windows 仅address=8000)。
第二步:IDE 配置远程调试(以 IntelliJ IDEA 为例)
- Run → Edit Configurations → + → Remote JVM Debug
- Host:
localhost(若在本机)或192.168.56.101(若在虚拟机) - Port:
8000 - 点击 Debug,IDE 底部显示
Connected to the target VM即成功。
此时可在org.apache.catalina.core.StandardWrapperValve.invoke()方法首行打条件断点,例如:
// 断点条件:只在请求路径含 "/api/user" 时触发 request.getRequestURI().contains("/api/user")这样,当curl http://localhost:8080/api/user/list时,IDE 自动停在invoke(),可逐行步入filterChain.doFilter(),看清哪个 Filter 抛出了NullPointerException。
6.2 JMX 远程监控:用 JConsole 实时查看线程、内存、Servlet 请求计数
Tomcat 8.5.100 内置 JMX MBean,无需额外 agent。启用只需在setenv.sh中加:
export JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=localhost"注意:
-Djava.rmi.server.hostname必须设为可被 JConsole 解析的地址。若在 Docker 中运行,需设为宿主机 IP(如172.17.0.1),否则 JConsole 连接后看不到 MBean。
启动后,运行jconsole(JDK 自带),在Remote Process输入localhost:9999,连接成功后切换到MBeans标签页,展开Catalina→type=GlobalRequestProcessor→name=http-nio-8080,即可实时查看:
requestCount:总请求数processingTime:总处理毫秒数maxTime:单次最长耗时errorCount:5xx 错误数
更进一步,可订阅Catalina:type=ThreadPool,name="http-nio-8080"的currentThreadCount,当该值持续 > 190(接近maxThreads=200),说明线程池打满,需排查慢 SQL 或阻塞 IO。
6.3 验证 JMX 数据:用jmxterm命令行批量采集指标
图形化 JConsole 适合人工排查,但自动化监控需命令行工具。jmxterm是轻量级 CLI,支持脚本化采集:
# 下载 jmxterm-1.0.2.jar(官网或 Maven 仓库) curl -O https://github.com/jiaqi/jmxterm/releases/download/v1.0.2/jmxterm-1.0.2-uber.jar # 连接并获取 requestCount echo "get -s Catalina:type=GlobalRequestProcessor,name=\"http-nio-8080\" requestCount" | \ java -jar jmxterm-1.0.2-uber.jar -l localhost:9999 -n # 输出示例:requestCount = 1245;将其写入定时任务,每分钟采集一次,存入 InfluxDB,即可绘制 Tomcat QPS 趋势图。
从那以后我每次上线新版本,都强制走一遍jconsole连接 +jstack <pid>线程快照 +jstat -gc <pid>内存统计三连,哪怕只花 90 秒。不是怕出问题,是怕问题来了找不到根因。希望帮到你。
本文还有配套的精品资源,点击获取