升级Tomcat 9反而不兼容被迫降到7.99——一次真实的迁移踩坑背景接手一个政务应用的部署。服务器环境比较新想着Tomcat已经出到10了至少上个Tomcat 9不过分吧结果部署上去应用启动了但访问页面各种报错。折腾了半天最后降级到Tomcat 7.99才跑通。这篇文章记录一下踩坑过程给还在用老Java应用的人提个醒。环境信息应用基于JSP Servlet MyBatis的政务OA系统Java版本JDK 8原Tomcat版本Tomcat 7.x目标Tomcat版本Tomcat 9.0.x最终方案Tomcat 7.99Tomcat 7的最后一个版本踩坑点坑一JSP编译失败——javax → jakarta这是最直接的错误。启动后访问JSP页面直接白屏catalina.out里报错org.apache.jasper.JasperException: Unable to compile class for JSP: An error occurred at line: [X] in the generated java file: [XXX] The import javax.servlet cannot be resolved原因Tomcat 9还是用javax.servlet但Tomcat 10开始改成了jakarta.servlet。这个问题在Tomcat 9上不应该出现——如果出现说明项目里可能混用了不同版本的Servlet API。但我们的问题不在这里。真正的坑在下面。坑二过滤器/监听器加载顺序变化Tomcat 9对web.xml的解析顺序和Tomcat 7有些细微差别。我们的应用依赖一个自定义的Filter做权限校验和用户上下文初始化这个Filter在Tomcat 7下工作正常在Tomcat 9下出现初始化顺序错乱——Filter在ServletContext还没完全初始化时就开始执行。表现是Filter里取ServletContext.getAttribute()拿到null后续逻辑全部走异常分支。临时处理在Filter里加null判断延迟初始化。根本原因Tomcat 9的Servlet容器初始化流程做了一些调整某些以前能依赖的初始化顺序不再保证。坑三类加载器变化导致jar冲突这是最难排查的问题。应用启动正常但部分功能报ClassNotFoundException或NoSuchMethodError。java.lang.NoSuchMethodError: org.apache.commons.lang3.StringUtils.isBlank(Ljava/lang/String;)Z原因Tomcat 9的类加载器机制和Tomcat 7不同。Tomcat 7对WEB-INF/lib下的jar优先加载Tomcat 9引入了WebappClassLoaderBase对双亲委派的实现有调整。表现应用带了一个新版本的commons-lang3但Tomcat 9先加载了自身或其他位置的老版本。应用调新方法实际跑的是老版本NoSuchMethodError。排查方法# 打印类加载来源-verbose:class# 或-XX:TraceClassLoading在catalina.sh里加上JAVA_OPTS$JAVA_OPTS -verbose:class启动后看目标类是从哪个jar加载的。坑四URIEncoding默认值不同Tomcat 7的server.xml里默认没有设置URIEncoding但Tomcat 9对URL编码的处理更严格。GET请求传中文参数Tomcat 7下能正常接收Tomcat 9下乱码。解决在server.xml的Connector里明确设置Connectorport8080protocolHTTP/1.1connectionTimeout20000URIEncodingUTF-8useBodyEncodingForURItrue/坑五JasperJSP引擎更严格的EL表达式校验Tomcat 9的Jasper对EL表达式的校验比Tomcat 7严格。原来Tomcat 7下能跑但不太规范的EL表达式在Tomcat 9下直接报错org.apache.el.parser.ELException: Error [XXX]: The identifier [YYY] is not a valid Java identifier我们的JSP页面里有些EL表达式用了不太规范的命名比如带连字符的变量名Tomcat 9不认了。最后的决定降级到Tomcat 7.99排查了一圈发现每个问题单独解决都不难但合在一起工作量太大。项目里有几百个JSP改完EL表达式和Filter逻辑就要好几天而且每个功能都要回归测试。Tomcat 7的最后一个版本是7.99虽然叫7但这个版本修复了大量的安全漏洞。对于我们这个不需要Java EE新特性的老项目来说Tomcat 7.99是最务实的选择。# 确认版本apache-tomcat-7.0.109# 7.x最后一个release版本Tomcat 7.99即7.0.99修复了45个CVE漏洞这个内容后面单独写一篇安全性和Tomcat 9相比差距不大兼容性却好得多。升级还是不升级方案优点缺点升级Tomcat 9新特性、长期支持、社区活跃兼容性改动大、回归测试工作量大降级Tomcat 7.99零改动、零风险官方已停止维护、部分新安全补丁可能滞后升级Tomcat 8.5折中方案、兼容性比9好、仍在维护中需要少量适配换Spring Boot内嵌Tomcat彻底解决问题架构大改不现实对于我们的老项目Tomcat 8.5其实是最合理的折中方案。8.5的兼容性比9好很多而且还在active维护中。当时为了快速交付选了7.99后续可以考虑过渡到8.5。如果一定要升级Tomcat 9需要做的改动清单检查所有Filter和Listener的初始化逻辑确保不依赖特定的加载顺序检查JSP中的EL表达式修正不规范的命名检查server.xml明确设置URIEncodingUTF-8检查jar包冲突用-verbose:class排查类加载来源检查JDBC驱动的兼容性确保ojdbc版本支持全面回归测试——每个页面、每个功能都要点一遍总结Tomcat大版本升级不是改个版本号就完事的。JSP/Servlet应用对Tomcat版本的依赖很深尤其是那些能跑但不太规范的代码换个大版本就炸。老项目升级的优先级建议先确保安全升级到当前大版本的最新patch再考虑跨大版本升级。Tomcat 7.99虽然老但它修了漏洞能跑就是硬道理。务实第一时髦第二。感谢豆包、智谱、OpenCode在写作过程中的辅助。