
Spring Boot 3.0 Java 17 升级实战解决 Shiro 的 javax.servlet.Filter 兼容性问题最近在将项目从 Spring Boot 2.7 升级到 3.0 的过程中遇到了一个典型的兼容性问题Shiro 报错java.lang.ClassNotFoundException: javax.servlet.Filter。这个问题看似简单但背后却隐藏着 Java EE 到 Jakarta EE 的重大变迁。本文将详细记录我的解决过程并分享一些升级中的实用技巧。1. 问题现象与初步分析当我在 Spring Boot 3.0.6 Java 17 环境下运行集成了 Shiro 的项目时控制台抛出了以下异常java.lang.ClassNotFoundException: javax.servlet.Filter at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)这个错误看起来像是缺少 Servlet API 的依赖但实际上问题更为复杂。经过排查我发现项目确实已经包含了javax.servlet:javax.servlet-api依赖同样的配置在 Spring Boot 2.7 中运行正常错误仅在升级到 Spring Boot 3.0 后出现这让我意识到问题可能与 Spring Boot 3.0 引入的重大变更有关。2. 深入理解 Jakarta EE 的命名空间变更Spring Boot 3.0 的一个重大变化是全面转向 Jakarta EE 9。这意味着所有javax.*包名已迁移到jakarta.*Servlet API 从javax.servlet变为jakarta.servlet这一变更影响了所有依赖 Servlet API 的库关键时间线版本变化影响Java EE 8使用javax.*命名空间传统标准Jakarta EE 9迁移到jakarta.*需要适配Spring Boot 3.0基于 Jakarta EE 9强制使用新命名空间这种命名空间的变更导致了许多依赖javax.servlet的库在 Spring Boot 3.0 环境下无法正常工作Shiro 就是其中之一。3. Shiro 的 Jakarta 适配方案幸运的是Shiro 团队已经为 Jakarta EE 提供了适配版本。解决方案的核心是使用 Maven 的classifier标签来指定 Jakarta 适配版本。3.1 基础配置首先我们需要修改 Shiro 的依赖声明dependency groupIdorg.apache.shiro/groupId artifactIdshiro-spring/artifactId classifierjakarta/classifier version1.11.0/version /dependency这个简单的改动就能解决大部分问题但实际情况往往更复杂。3.2 处理传递依赖问题Shiro 的一些子模块可能仍然依赖javax.servlet版本。为了彻底解决问题我们需要排除有问题的传递依赖显式引入 Jakarta 适配版本完整配置如下dependency groupIdorg.apache.shiro/groupId artifactIdshiro-spring/artifactId classifierjakarta/classifier version1.11.0/version !-- 排除仍使用了javax.servlet的依赖 -- exclusions exclusion groupIdorg.apache.shiro/groupId artifactIdshiro-core/artifactId /exclusion exclusion groupIdorg.apache.shiro/groupId artifactIdshiro-web/artifactId /exclusion /exclusions /dependency !-- 引入适配jakarta的依赖包 -- dependency groupIdorg.apache.shiro/groupId artifactIdshiro-core/artifactId classifierjakarta/classifier version1.11.0/version /dependency dependency groupIdorg.apache.shiro/groupId artifactIdshiro-web/artifactId classifierjakarta/classifier version1.11.0/version exclusions exclusion groupIdorg.apache.shiro/groupId artifactIdshiro-core/artifactId /exclusion /exclusions /dependency3.3 Gradle 配置方案对于使用 Gradle 的项目可以这样配置implementation(org.apache.shiro:shiro-spring:1.11.0:jakarta) { exclude group: org.apache.shiro, module: shiro-core exclude group: org.apache.shiro, module: shiro-web } implementation org.apache.shiro:shiro-core:1.11.0:jakarta implementation(org.apache.shiro:shiro-web:1.11.0:jakarta) { exclude group: org.apache.shiro, module: shiro-core }4. 验证与测试配置完成后建议进行以下验证步骤依赖树检查运行mvn dependency:tree或gradle dependencies确认没有javax.servlet相关的依赖启动测试确保应用能正常启动没有ClassNotFoundException功能测试验证 Shiro 的核心功能认证、授权等是否正常工作提示如果仍然遇到问题可以尝试清理 Maven/Gradle 缓存有时旧的依赖会被缓存导致问题。5. 升级中的其他常见问题除了 Shiro 的问题升级到 Spring Boot 3.0 Java 17 还可能会遇到Hibernate 兼容性确保使用 Hibernate 6.0 版本第三方库适配检查其他依赖是否有 Jakarta EE 适配版本构建工具配置Maven/Gradle 可能需要更新插件版本推荐升级检查清单确认所有核心依赖都有 Jakarta EE 适配版本检查构建工具和插件的兼容性准备回滚方案以防遇到无法解决的问题分阶段升级先解决编译问题再处理运行时问题6. 深入理解 Maven classifier 机制这次解决问题的关键是通过classifier指定了 Jakarta 适配版本。classifier是 Maven 依赖管理中的一个强大但常被忽视的特性。classifier 的常见用途指定不同构建版本如jakarta、javax区分不同平台如linux-x86_64、windows-x86_64提供附加功能版本如sources、javadoc使用建议优先查看官方文档了解是否有特定 classifier 可用在解决兼容性问题时classifier 往往是简单有效的方案注意 classifier 可能会影响依赖解析需要全面测试7. 长期维护建议随着 Jakarta EE 的普及未来可能会有更多库需要类似处理。建议保持依赖更新定期检查依赖的 Jakarta 适配状态建立兼容性矩阵记录各库的兼容版本信息自动化测试增加版本兼容性相关的测试用例在实际项目中我们建立了一个简单的兼容性检查工具可以在构建时自动检测潜在的javax.*引用这大大减少了升级过程中的问题排查时间。