别再被 ClassNotFoundException 困扰详解 Shiro 1.11.0 在 Spring Boot 3 中的正确引入姿势Jakarta 适配版最近在升级到 Spring Boot 3.0 的项目中集成 Shiro 时不少开发者遇到了令人头疼的ClassNotFoundException: javax.servlet.Filter错误。这实际上是 Java EE 向 Jakarta EE 演进过程中的一个典型兼容性问题。本文将带你深入理解问题根源并提供一套完整的解决方案。1. 问题根源从 Java EE 到 Jakarta EE 的演进2017 年Oracle 将 Java EE 移交给了 Eclipse 基金会随后 Java EE 更名为 Jakarta EE。这一变更不仅仅是名称上的改变还带来了包名的重大调整旧版javax.servlet.*新版jakarta.servlet.*Spring Boot 3.0 完全基于 Jakarta EE 9 规范构建这意味着它只识别jakarta.servlet.*包。而 Shiro 作为一个历史悠久的框架其默认依赖仍使用javax.servlet.*包结构。关键冲突点Spring Boot 3.0 (Jakarta) ←→ Shiro 1.11.0 (默认使用 javax)2. Shiro 的 Jakarta 适配方案Apache Shiro 团队已经预见到了这一兼容性问题从 1.11.0 版本开始提供了 Jakarta 适配版本。这些适配版本通过 Maven 的classifier机制提供dependency groupIdorg.apache.shiro/groupId artifactIdshiro-spring/artifactId version1.11.0/version classifierjakarta/classifier !-- 关键配置 -- /dependency但事情并没有这么简单。由于 Shiro 的模块化设计某些子模块如shiro-core和shiro-web可能仍然会引入 javax 版本的传递依赖。3. 完整解决方案Maven 配置指南以下是经过实战验证的完整 Maven 配置方案!-- 主依赖配置 -- dependency groupIdorg.apache.shiro/groupId artifactIdshiro-spring/artifactId version1.11.0/version classifierjakarta/classifier 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 version1.11.0/version classifierjakarta/classifier /dependency dependency groupIdorg.apache.shiro/groupId artifactIdshiro-web/artifactId version1.11.0/version classifierjakarta/classifier exclusions exclusion groupIdorg.apache.shiro/groupId artifactIdshiro-core/artifactId /exclusion /exclusions /dependency注意这种显式排除和重新引入的方式确保了所有相关模块都使用 Jakarta 适配版本避免了 javax 和 jakarta 混用导致的类加载问题。4. Gradle 用户的适配方案对于使用 Gradle 构建的项目配置方式略有不同dependencies { 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 } }5. 验证依赖配置的正确性配置完成后建议通过以下方式验证依赖树Maven 项目mvn dependency:treeGradle 项目gradle dependencies在输出中检查所有 Shiro 相关依赖是否都带有jakarta分类器且没有 javax.servlet 的传递依赖。6. 常见问题排查即使按照上述步骤配置仍可能遇到一些问题IDE 缓存问题执行 clean 操作重新导入 Maven/Gradle 项目版本冲突确保所有 Shiro 模块版本一致均为 1.11.0检查是否有其他依赖引入了 javax.servlet运行时异常如果仍出现类找不到异常尝试添加以下依赖dependency groupIdjakarta.servlet/groupId artifactIdjakarta.servlet-api/artifactId version5.0.0/version scopeprovided/scope /dependency7. 深入理解 Shiro 的 Jakarta 适配机制Shiro 的 Jakarta 适配实际上是通过重新编译源代码实现的主要变更包括包导入从javax.*改为jakarta.*保持相同的 API 签名和行为使用 Maven 分类器机制提供并行版本这种设计允许项目同时维护 javax 和 jakarta 两个版本而不需要改变主版本号。版本兼容性对照表Shiro 版本Jakarta 支持Spring Boot 兼容性1.10.x不支持仅兼容 Spring Boot 2.x1.11.0通过分类器支持兼容 Spring Boot 3.x2.0原生支持未来版本8. 最佳实践建议版本锁定在 dependencyManagement 中固定 Shiro 版本避免不同模块使用不同版本的 Shiro持续关注更新Shiro 2.0 将原生支持 Jakarta EE考虑未来迁移计划测试策略增加集成测试验证权限功能特别关注 Filter 相关的功能测试备选方案评估对于新项目可以考虑 Spring Security 等原生支持 Jakarta EE 的替代方案评估迁移成本和功能需求在实际项目中我遇到过这样一个案例一个团队花了三天时间排查权限失效问题最终发现是因为测试环境使用了旧的构建缓存。这个教训告诉我们在解决这类兼容性问题时干净的构建环境和完整的依赖验证是多么重要。