
Spring Boot 3.0 Java 17 整合 Shiro 的完整迁移实战从 javax.servlet 到 jakarta.servlet 的深度解析最近在将一个老项目升级到 Spring Boot 3.0 和 Java 17 时遇到了一个典型的踩坑场景整合 Shiro 时抛出了ClassNotFoundException: javax.servlet.Filter错误。这个看似简单的错误背后实际上隐藏着 Java EE 到 Jakarta EE 的演进历史。本文将带你深入理解这个问题并提供一套完整的解决方案。1. 问题背景与根源分析当你在 Spring Boot 3.0 项目中尝试集成 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 的包名变更。从 Java EE 到 Jakarta EE 的转变过程中最显著的变化之一就是包名的迁移Java EE 时代javax.servlet.*Jakarta EE 时代jakarta.servlet.*Spring Boot 3.0 基于 Servlet 5.0 规范已经完全迁移到了 Jakarta EE 9 的命名空间。而许多老版本的库包括 Shiro 的某些模块仍然使用旧的javax.servlet包名这就导致了类加载失败。提示这个迁移不仅仅是简单的包名替换还涉及到一些 API 的细微变化因此需要特别注意兼容性问题。2. 解决方案全景图解决这个问题的完整方案包含以下几个关键步骤使用 Shiro 的 Jakarta 兼容版本Shiro 1.11.0 提供了专门适配 Jakarta 的版本排除冲突的依赖确保项目中不会混用 javax 和 jakarta 版本的 Servlet API验证依赖树使用 Maven 或 Gradle 工具检查依赖关系2.1 关键 Maven 配置以下是经过验证的完整 pom.xml 配置片段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 /dependency2.2 配置解析这个配置有几个关键点classifierjakarta/classifier指定使用 Jakarta 兼容版本exclusions排除仍然依赖 javax.servlet 的子模块版本一致性确保所有 Shiro 组件使用相同版本3. 深入理解依赖冲突为了彻底解决问题我们需要深入理解 Maven 依赖树。可以使用以下命令查看依赖关系mvn dependency:tree -Dincludesorg.apache.shiro典型的依赖冲突场景可能如下表所示问题依赖冲突表现解决方案shiro-core依赖 javax.servlet使用 jakarta 分类器版本shiro-web传递依赖旧版 shiro-core显式排除并引入正确版本shiro-spring内部依赖未迁移的组件排除后单独配置注意在实际项目中可能还需要检查其他间接依赖是否引入了 javax.servlet API确保完全清除所有冲突源。4. 完整集成步骤4.1 环境准备确保你的开发环境满足以下要求JDK 17Spring Boot 3.0Maven 3.6 或 Gradle 74.2 分步集成指南添加基础依赖首先添加 Spring Boot 和 Shiro 的基础依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency配置 Shiro Jakarta 版本使用前面提供的完整配置添加 Shiro 依赖。创建 Shiro 配置类Configuration public class ShiroConfig { Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager new DefaultWebSecurityManager(); // 配置 Realm 等组件 return securityManager; } Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean filterFactoryBean new ShiroFilterFactoryBean(); filterFactoryBean.setSecurityManager(securityManager); // 配置过滤规则 return filterFactoryBean; } }验证配置启动应用并访问端点确保没有出现类加载错误。4.3 常见问题排查如果按照上述步骤配置后仍然遇到问题可以检查以下几点依赖树是否干净再次运行mvn dependency:tree确认没有 javax.servlet 残留版本一致性确保所有 Shiro 组件版本一致IDE 缓存问题尝试清理并重新导入 Maven 项目5. 迁移后的注意事项成功迁移后还需要注意以下事项测试覆盖确保所有权限控制逻辑仍然正常工作性能监控观察系统性能确保没有因版本变更引入性能问题第三方集成检查其他与 Shiro 集成的组件是否兼容 Jakarta 版本在实际项目中我还发现了一些有用的技巧使用 Maven 的dependency:analyze目标可以帮助识别未使用的依赖在大型项目中可以分模块逐步迁移而不是一次性全部切换建立专门的测试用例来验证权限控制逻辑的正确性