简介:这是一份面向 Linux 环境的 Tomcat 8.5.35 安装包,适合后端开发、运维人员以及需要搭建 Java Web 服务的入门学习者。压缩包包含完整发行组件,解压后即可获得 Catalina、Jasper、Coyote 等核心模块,支持 Servlet、JSP、WebSocket 与 Java EE 8 规范。包体共 645 个文件,约 9.2MB,主要涵盖 HTML 页面、Java 类与源码、JSP 页面、JAR 库、XML 配置、Shell 启动脚本及 GIF/PNG 图标等,既可支撑直接部署,也为二次开发提供了参考。已有 555 人学习下载。内部保留 bin、conf、lib、logs、temp、webapps、work 等标准目录结构:bin 放置启动与停止脚本,conf 保存核心服务器配置,lib 存放运行所需 JAR 依赖,webapps 用于投放应用包,work 记录 JSP 编译产物与临时数据。其中 class 文件与 Java 源码并存,适合在排错或定制功能时对照查看;XML 配置和 Shell 脚本则覆盖了日常启停、端口调整、安全加固等常见运维操作。整体体积小巧、版本稳定,适合在 Linux 服务器上快速搭建可靠、可扩展的 Java Web 运行环境。
1. 为什么这个 tar 包让不少人在 Linux 上就是一遍过
Tomcat 8.5.35 的 Linux tar.gz 包是 Java 8 时代最常见的应用容器安装包:它提供了解压即用的目录结构,只要 JAVA_HOME 指对、端口和权限没被占,启动就是一条命令的事。这一个版本正好卡在 javax 命名空间和 Java 8 兼容性的舒适区,很多老的业务系统都愿意钉在它上面。适合刚接手 Linux 服务器、想自己布一个能跑 war 的 Java 环境的人,也适合在多个机器上批量铺同版本容器的运维同学。后面所有步骤都在这个版本上验证过,照着做,基本不会出现“教程说得通、自己跑不通”的断档。
2. 装之前把三件事定下来:JDK、tar 包校验和目录规划
2.1 先确认 JDK 8 和 8.5.35 是否真的匹配
Tomcat 不捆绑 JDK,它只是消费一个已经装好的 Java 运行时。8.5.35 在编译期需要 Java 7 以上的 JDK 才能运行,但在实际部署里,我一般只推荐配对 Java 8。一个原因是 8.5.x 中期的很多类加载和反射路径都在 Java 8 上被反复验证过,换到 Java 11 或更高版本容易出现“能启动但个别功能报 NoClassDefFoundError”的隐性问题;另一个原因是这个版本诞生年代正好是 Java 8 大规模铺开的时候,配套的旧项目、旧插件也都是按 Java 8 写的。
还有个容易被忽略的点:系统自带的 java 命令未必是你要的那个。Linux 上多版本 JDK 共存是常态,命令行里敲 java -version 返回的可能来自某个其它路径,而 Tomcat 的启动脚本判断 JAVA_HOME 用的是环境变量,不依赖 PATH。所以安装 Tomcat 前,我会先写死 JAVA_HOME,而不是等着从 PATH 里继承。检查当前默认 Java 的做法很简单:
java -version echo $JAVA_HOME如果输出的版本和你预期不一致,先不要往下解压,先把环境变量问题解决。否则后面所有启动报错都会指向同一个原因:找不到 JAVA_HOME,但真正问题其实是 PATH 里那个 java 指向了别处。这一步花三十秒,能省掉后面一小时排错。我自己的习惯是准备一个专门记录 Java 安装路径的小本子,每台机器装完先写一行,避免多个服务器来回切换时记混。
2.2 下载和校验:不是解压完就完事
拿到 Linux 版本 tomcat8-8.5.35.tar.gz 之后,第一步先确认文件大小是否合理。Tomcat 官方发布的 tar.gz 一般只有十几到几十 MB,因为它不捆绑 JDK,也不带一堆运行时。如果下载来源显示这个包超过 200MB,十有八九是个改过的版本,直接换源。下载完成后,我会先对一下校验值再解压:
sha256sum tomcat8-8.5.35.tar.gz # 输出结果和发布页给出的 SHA256 值比对,一致再继续这里用 SHA256 而不是 MD5:MD5 在现代场景下已经能被碰撞,为了做一个可复现的完整性基线,至少要用 SHA256。校验值对不上时,常见处理是重新下载一次,偶尔是网络代理缓存了损坏分片导致。注意要以发布页同一个链接下的校验文件为准,不要拿旧链接的校验值硬套。
解压这一步我一般放进规划的安装路径父目录,而不是先解压到临时目录再移动。移动大目录会遇到属主、权限位丢失的问题,而且临时目录的文件可能被清理任务误删。解压命令是:
cd /opt tar -xzf /root/software/tomcat8-8.5.35.tar.gz ls -d */ # 确认解压出的目录名 ln -s /opt/apache-tomcat-8.5.35 /opt/tomcat # 目录名以实际解压结果为准参数说明:-x 是解包,-z 是解压 gzip,-f 指定文件名。解压后建立一个软链接 /opt/tomcat 指向真正的版本目录。这样做的原因是:以后升级就把新版本解压成新目录,然后改一下软链接指向,业务脚本里写路径不用跟着改。如果跳过软链接直接使用版本号目录,每次升级都要同步改所有配置文件,迟早漏一处。这个“版本目录 + 软链接固定名”的做法,在多个 Java 服务并存时特别有用。
2.3 解压后目录里每一层是干什么的
解压完成后,安装目录下会看到 bin、conf、lib、logs、temp、webapps、work 这七个一级目录。很多人一上来就盯着 conf/server.xml 改,其实先花两分钟把目录职能过一遍,后面排查问题会快很多。
bin 目录里是启动和停止脚本。startup.sh 和 shutdown.sh 是给用户直接调用的入口,catalina.sh 是真正的执行主体,接收 start、stop、run 这些参数。conf 目录是所有配置文件的集中地:server.xml 管端口和 Host,web.xml 管全局 Servlet 默认配置,context.xml 管全局上下文参数。logs 目录是运行时日志的输出位置,catalina.out 是主日志。webapps 目录是 war 包放置位置,默认部署就是丢进去然后等自动解压。work 目录是 JSP 编译后的 class 缓存,遇到改 JSP 不生效的怪问题时,先清这个目录。
还有一个容易忽略的是 temp 目录。Tomcat 运行时常往 temp 写临时文件,如果这个目录被系统定时清理脚本误删,会出现启动时正常、运行一段时间后偶发找不到临时文件的现象。所以我不建议把 Tomcat 放进 /tmp 下面,而是放在 /opt 这种稳定的业务分区。如果机器上只有一块盘,至少保证日志目录所在分区的剩余空间是 war 包体积的三倍以上,因为解压后的目录树有大量小文件,磁盘 inode 耗尽也会表现为“创建文件失败”。这一步和第 4 章的几个坑都有关系,提前规划好能省掉后续很多麻烦。
装前的三件事到这里就齐了:JDK 对齐、校验比对、目录规划。这些基础打稳,真正启动时的故障率会直线下降。
3. 让 Tomcat 跑起来:三处关键配置和启动验证
3.1 JAVA_HOME 写到哪里:setenv.sh 是受控入口
Tomcat 启动脚本读取环境变量是有顺序的:catalina.sh 会先加载 bin/setenv.sh(如果存在),再用这个文件里的变量覆盖系统级的 export。所以自定义环境变量要写进 setenv.sh,而不是直接改 catalina.sh。直接改 catalina.sh 的问题在于升级时新版本会覆盖这个文件,而 setenv.sh 是官方预留的自定义入口,升级后依然保留,不会被覆盖。
创建 setenv.sh 并写入 JAVA_HOME:
cat > /opt/tomcat/bin/setenv.sh <<'EOF' JAVA_HOME=/usr/local/jdk1.8.0_202 JRE_HOME=$JAVA_HOME/jre CATALINA_HOME=/opt/tomcat CATALINA_BASE=/opt/tomcat EOF chmod +x /opt/tomcat/bin/setenv.sh参数说明:JAVA_HOME 指向 JDK 安装路径,这里顺手写了 JRE_HOME,其实 8.5.35 只要 JAVA_HOME 配置正确,JRE_HOME 可以省略,但写上之后对旧版脚本兼容性更好。CATALINA_HOME 是 Tomcat 安装根目录,CATALINA_BASE 在单实例下和 CATALINA_HOME 相同,多实例时每个实例指向自己的目录。这里用 heredoc 方式创建文件,好处是文件内容不会被执行 shell 展开,路径里的特殊字符都能原样保留。
注意这个文件里的变量不会自动导出到系统全局环境变量,它只在 Tomcat 的启动脚本里生效。如果还希望 SSH 登录后能直接敲 catalina 命令,需要在 /etc/profile.d/ 下追加脚本,但那不是必须的。我见过有人在 setenv.sh 里写 export 后以为改的是全局,结果机器重启后环境变量消失,又回来排查半天。养成“环境变量归属清晰”的习惯,这类玄学问题就能少一大半。
3.2 server.xml:端口、连接数与 Host 配置的推荐初值
conf/server.xml 是 Tomcat 主配置文件。新手最常见的做法是只改 HTTP 端口号就收工,但在 8.5.35 上,还有几个参数值得在部署前一次性设置好。下面是一个比较完整的 Connector 配置:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" maxThreads="200" minSpareThreads="10" acceptCount="100" redirectPort="8443" maxPostSize="10485760" URIEncoding="UTF-8"/>逐项说明:port 是监听端口,建议不要用 8080 裸奔,改成不常见的端口比如 18080,至少能少挨一点扫描脚本的骚扰。connectionTimeout 是客户端建立连接后读请求的超时时间,单位毫秒,20000 对大多数业务足够。maxThreads 是处理 HTTP 请求的最大工作线程数,决定 Tomcat 同时能处理多少请求;minSpareThreads 是空闲时保持的最小线程数,防止请求突发时现场建线程。acceptCount 是请求队列长度,当线程全部忙时,新请求会进队列等待。
这两个参数要配合看:maxThreads + acceptCount 不是越大越好,因为 Linux 每个线程都要占栈空间,200 个线程对应 1MB 线程栈就是 200MB 虚拟内存,设置过大会给 JVM 的堆带来额外压力。maxPostSize 是表单提交的最大字节数,默认是 2MB,如果你的业务要上传大文本或 base64 内容,默认值很容易触发报错,改成 10485760(10MB)是一个常见的起步值。URIEncoding 在 8.5.x 默认已是 UTF-8,显式写出来是为了给后来维护的人一个提示:中文参数乱码并不是改这里能解决的,先检查前端页面编码和数据库字符集。
Host 节点里常用的配置是 appBase 和 autoDeploy。appBase 是 webapps 目录路径,默认是 webapps;autoDeploy 决定是否自动部署新放入的 war 包。生产环境我习惯把 autoDeploy 设为 false,因为线上发布应该走受控流程,而不是一丢文件就自动挂载,导致正在被访问的应用被 reload 打断。另外 Server 标签里默认 shutdown 端口是 8005,密码是 SHUTDOWN,这个端口一定不要暴露到公网,最省心的做法是只监听本机回环地址。
3.3 启动、停止和确认“真的起来了”
配置完成后,第一个启动命令很多人会直接敲 startup.sh。这条命令的本质是让 Tomcat 后台启动,用 nohup 方式把 JVM 进程拉起来,日志写到 logs/catalina.out。启动后马上会遇到的困惑是:命令返回了,但不知道成功没有。
/opt/tomcat/bin/startup.sh tail -f /opt/tomcat/logs/catalina.out启动脚本会在终端输出 Tomcat started 以及耗时,但真正能说明问题的是 catalina.out 里的最后几行。如果看到 INFO: Server startup in [xxx] milliseconds,那才是启动完成。只有 Starting 看不到下文,多半是端口没起来或者 Host 配置解析失败。
验证方式有三种,从外到内:
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:18080/ jps -l | grep Bootstrap netstat -tlnp | grep 18080curl 返回 200 说明 HTTP 层正常;jps 里能看到 org.apache.catalina.startup.Bootstrap 进程,说明 JVM 层的主进程活着;netstat 确认端口在监听。这三条同时满足,才算这一轮启动真正通过。如果 curl 返回连接拒绝但 jps 有进程,问题大概率在端口配置或防火墙,先看 netstat 和 server.xml 是否一致。如果 jps 都没有这个 Java 进程,回 catalina.out 末尾看异常栈,基本能定位到具体哪一行配置出错。这套验证顺序我一直习惯用,每次都能把“到底起没起来”的争论直接终结。
4. Tomcat 8.5.35 部署中的五个高频坑与排查思路
先说结论:Tomcat 的报错信息已经写得相当直白,多数启动失败在 catalina.out 前二十行就能定位。真正浪费时间的,是那些“日志没报错但行为不对”的问题。这一章讲五个从实际部署里拎出来的坑,每条都按现象、原因、解决的顺序写。
4.1 明明装了 JDK,启动却说找不到 JAVA_HOME 或 JRE_HOME
现象:执行 startup.sh 后终端直接打印 Neither the JAVA_HOME nor the JRE_HOME environment variable is defined,随后退出。 原因:catalina.sh 判断的是环境变量,而不是仅仅看 PATH 里有没有 java。很多机器上 java 是通过软链接或版本管理工具动态加载的,shell 里敲 java 能用,但 JAVA_HOME 从未被导出。这类问题在使用系统自带包管理器安装 Java 时特别常见。 解决:不要往 /etc/profile 里乱加,而是在 setenv.sh 里显式写死 JAVA_HOME 绝对路径,写完后重新登录会话再启动。判断是否生效的办法是 echo $JAVA_HOME,能打印出路径才算导出成功。这里有个容易翻车的细节:setenv.sh 里的 JAVA_HOME 赋值要写绝对路径,不能写成 JAVA_HOME=$(which java) 这种动态取值,因为 which 解析出来的往往是软链接路径,真正的 JDK home 在链接的上一层。这个原因几乎解释了我见过的一半“明明装了就说不存在”的案例。
4.2 改完端口还是访问不到,防火墙拦截在背锅
现象:catalina.out 显示启动成功,本机 curl 127.0.0.1:8080 有响应,但从另一台机器访问超时或连接拒绝。 原因:Tomcat 监听没问题,问题出在系统层面的包过滤。常见的是防火墙规则未放行新端口,或者 SELinux 对非标准端口有拦截策略。 解决:先确认 Tomcat 确实在监听,用 ss -tlnp | grep 18080 看监听地址,再给防火墙放行。注意不要为了省事直接关掉防火墙,只放行必要端口就好。如果机器开了 SELinux,还需要用对应工具把端口加入允许列表。这一类问题的排查要诀是:先本地再跨机,先端口再防火墙,不要一上来怀疑 Tomcat 配置。我见过有人在 server.xml 里改了三遍端口,最后发现是防火墙规则把所有高端口都 drop 了,和 Tomcat 一点关系都没有。
4.3 启动成功但 catalina.out 里没有日志,或者文件越写越大
现象:Tomcat 在跑,业务也正常,但 logs/catalina.out 长时间不更新,或者这个文件膨胀到几个 GB。 原因:catalina.out 是标准输出重定向文件,如果应用代码里的日志框架把输出定向到别的文件(比如用 logback 的 RollingFile),catalina.out 就不会有新内容。同时,System.out.print 这类原生日志如果被大量使用,且没配置轮转,文件就会一直增长,直到把磁盘填满。 解决:生产环境把业务日志交给日志框架管理,用 logback 或 log4j2 输出到独立文件并配置滚动策略。catalina.out 只保留启动信息和未捕获异常。如果 catalina.out 已经太大,收割日志前先确认业务日志在哪,然后清空它:
> /opt/tomcat/logs/catalina.out清空不需要停 Tomcat,因为 JVM 持有的是文件描述符而不是文件锁,用重定向清空内容不影响运行。这算是 Linux 下少见的“可以边跑边清”的场景,但要注意清空后要及时补上 logrotate 配置,否则同样的问题会再回来。
4.4 root 启动一时爽,日志权限埋雷
现象:用 root 执行 startup.sh 启动成功,后面切换计划任务或监控脚本去读日志时报权限不足,甚至应用自己无法写日志。 原因:root 启动后,logs 目录下的新文件属主都是 root,后续服务如果以普通用户身份运行或采集日志,会因权限不足读取失败。反过来,用普通用户启动时,如果 war 包临时目录 work 属主不对,JSP 编译也会失败。 解决:部署前先创建专用系统用户,把安装目录属主递交给它,再统一用这个用户启动:
useradd -r tomcat chown -R tomcat:tomcat /opt/tomcat su - tomcat -c '/opt/tomcat/bin/startup.sh'以后所有操作都在这个用户名下做。启动脚本里不要用 sudo 包裹,直接用 su 切换身份。这一步能规避后续一大堆权限类故障,特别是你有监控采集、日志转发这类自动化任务时,权限统一是减少抓狂前提。
4.5 解压后的目录缺少可执行权限,脚本报 Permission denied
现象:tar 包明明解压成功,执行 ./bin/startup.sh 时报 Permission denied,但 ls 看文件没有异常。 原因:tar 包本身在压缩文件里保留了可执行位,但如果你是通过某些 Web 管理页面或 FTP 工具上传的,文件流转过程中权限位被剥掉了。有些文件系统的挂载选项也会忽略 exec 权限。 解决:给脚本补上执行权限:
chmod +x /opt/tomcat/bin/*.sh执行后再跑 startup.sh。如果还报权限问题,检查所在分区是不是以 noexec 方式挂载的,用 mount 查看挂载选项。如果分区是 noexec,把 Tomcat 解压到非 noexec 分区即可。这个问题本身不复杂,但第一次碰到的人往往会怀疑是包损坏,重新下载一遍浪费时间,其实一行 chmod 就解决。
5. 让它更扛打:JVM 参数、线程池配置和 systemd 托管
5.1 JVM 内存参数:给 Tomcat 预留多大的堆才合理
默认情况下,Tomcat 的 JVM 启动参数沿用 Java 虚拟机的默认值。这里有个误解点:64 位 JDK 默认最大堆是物理内存的四分之一,听起来不小,但实际是它只在真正需要时才把堆撑到那个值,年轻代大小、垃圾回收策略都不会针对 Web 容器做优化。所以生产部署我会显式设置初始堆和最大堆,在 setenv.sh 里追加:
CATALINA_OPTS="-Xms512m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -Djava.awt.headless=true"参数说明:-Xms 是堆初始大小,-Xmx 是堆最大上限。设置 -Xms 的意义在于让 JVM 启动时就申请好内存,避免运行时缓慢扩张。堆大小怎么估算:按一台 2 核 4G 的虚拟机,Tomcat 独占的话,堆给 2G,留 1.5G 给系统缓存和线程栈。如果机器上还跑着数据库,堆就要压到 1G 以内,堆设得再大也只是和数据库争内存,性能反而更差。MetaspaceSize 是元空间的初始大小,Java 8 里取代了原来的 PermGen,不设上限的话,类加载特别多时会吃掉大量物理内存,所以设一个 MaxMetaspaceSize 兜底。headless=true 是为了在没有显示设备的 Linux 上让图片处理等 AWT 功能正常工作,不加它,某些报表导出功能会抛 HeadlessException。
这里必须提一个关键点:CATALINA_OPTS 里的参数只会传给 Tomcat 的 JVM 进程,而 JAVA_OPTS 是给所有 Java 相关脚本用的。在 catalina.sh 里,两个变量的加载位置不同。调 Tomcat 时用 CATALINA_OPTS 更精确,避免把堆参数泄漏给其它调用 Java 的脚本,否则可能出现“我只是配了 Tomcat 参数,结果某天另一个 Java 工具启动时报堆内存冲突”的怪事。
5.2 Connector 性能参数怎么配,先看请求特征
server.xml 里的 Connector 参数直接决定 HTTP 请求的吞吐上限。前面第 3 章已经给了推荐初始值,这里再补充怎么根据请求特征调整,而不是照抄默认值。默认配置下,Tomcat 的 maxThreads 是 200,acceptCount 是 100。如果应用是重 IO、低 CPU 的,比如对外提供文件下载,线程数可以适当调高,但要注意线程栈内存叠加。如果应用是重 CPU 计算的,比如大量加解密,线程数反而要调低,因为 CPU 核数就那么多,线程再多只是排队。
更重要的一个点是协议选择。8.5.35 默认的 HTTP/1.1 走的是 NIO 模型,不需要额外配 BIO。要确认当前用的是哪个模型,看启动日志里会出现 http-nio-8080 这样的协议名,看到 nio 就说明走的是 NIO。如果在 Connector 标签上加一个 executor 属性,可以把线程池统一管理起来,但引入后要特别注意 maxThreads 的归属:线程池里配的是全局共享上限,Connector 上的 maxThreads 会失效。很多人同一台机器上部署多个应用时踩过这个坑,以为每个 Connector 的 maxThreads 是隔离的,结果共用线程池后一个应用的慢请求把另一个拖死。所以引入 executor 前,先想清楚所有应用是不是同一个接口团队在维护,否则遇到线上互相拖累时很难分锅。
还有两个参数容易被忽略:connectionUploadTimeout 和 disableUploadTimeout。默认情况下,如果请求体上传时间较长,Tomcat 会在 connectionTimeout 后断开。虽然规范里有上传统计的逻辑,但显式设置这两个参数能避免慢网络下的误断开。这两个参数在做文件上传业务的系统里值得留一行注释,不然现场上传大文件时断连,运维第一反应是去调 Nginx 超时,调完发现没用才回头查 Tomcat,浪费大半天。
5.3 用 systemd 托管 Tomcat:开机自启与异常拉起
用 startup.sh 启动有个痛点:进程靠 nohup 在后台运行,机器一重启它不会自动恢复,进程异常退出后也没有看护。生产环境建议用系统自带的 systemd 来托管。先创建服务文件:
cat > /etc/systemd/system/tomcat.service <<'EOF' [Unit] Description=Tomcat 8.5.35 Service After=network.target [Service] Type=forking User=tomcat Group=tomcat Environment=CATALINA_HOME=/opt/tomcat Environment=CATALINA_BASE=/opt/tomcat ExecStart=/opt/tomcat/bin/startup.sh ExecStop=/opt/tomcat/bin/shutdown.sh Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable tomcat systemctl start tomcat配置项解释:Type=forking 表示启动脚本会 fork 出子进程后父进程退出,这正是 startup.sh 的行为。User 和 Group 指定运行身份,和第 4 章的权限坑呼应。Restart=on-failure 表示只有异常退出才重启,正常 stop 不触发。RestartSec 是重启前的等待秒数,给系统一点缓冲时间。enable 是设置开机自启,start 是立即启动。
用 systemd 托管后有一个明显变化:如果不在 service 里单独指定标准输出,Tomcat 的系统日志会被 journald 接管,用 journalctl -u tomcat 查看,而不是 catalina.out。停止服务时 systemd 会给 shutdown.sh 一个超时窗口,如果应用关闭太慢会收到 SIGKILL。有事务型长任务的系统要在应用侧处理优雅退出,不能指望脚本一刀切。第一次从手动启动切到 systemd,建议先在测试环境完整走一遍 start 和 stop,确认没有因为 shutdown 超时把进程杀掉,再上生产。
6. 老版本也有新用法:多实例、日志轮转和升级判断
6.1 单机多实例:用 CATALINA_BASE 隔离实例
如果一台机器要跑多个互相隔离的应用,不要整个复制 Tomcat 目录,而是新建一个实例目录作为 CATALINA_BASE,复制 conf、logs、temp、webapps、work 这五类目录,bin 和 lib 继续共享安装目录。新实例启动时用 -config 参数指定自己的 server.xml,同时保证 HTTP 端口、shutdown 端口、日志路径各自独立。这样一套 tar 包就能跑多个实例,最省资源。
6.2 日志轮转:用 logrotate 按天切分
生产环境给 catalina.out 加一条 logrotate 规则,按天和大小切分,保留 30 天:
/opt/tomcat/logs/catalina.out { daily rotate 30 size 100M copytruncate compress missingok }copytruncate 参数是关键。Tomcat 的 JVM 进程一直占着这个文件描述符,如果 logrotate 用默认的 rename 方式重命名,Tomcat 会继续往旧文件里写,新文件永远是空的。copytruncate 先复制当前内容到归档文件再清空原文件,不用重启 Tomcat,也就不会中断服务。
6.3 升级判断:别把旧版本当永久归宿
8.5.35 在 Java 8 场景下很稳,但后续版本一直在修安全通告。我会定期查看该小版本之后的安全修复列表,只要与自己的业务组件相关,就计划升级。升级路径建议走 8.5.x 最新版而不是跳到 10.x 大版本,因为前者兼容 javax 命名空间,war 包和 server.xml 基本不用动;后者要把 javax 换成 jakarta,迁移成本高出一截。我在生产线上吃过一次闷亏:为了图稳定一直钉在 8.5.35,后来安全扫描直接暴露旧版问题,被迫在业务低峰期紧急升级,加了一个通宵的班。那之后我给自己定的习惯是每个季度看一次这个版本的维护状态,不再留恋旧版本。把升级当成常规维护而不是事故演习,希望这次整理的安装、排查和调优流程,能帮把你 Tomcat 这条线管得更省心一些。
本文还有配套的精品资源,点击获取