导读:qkl-boot 脚手架要从 Spring Boot 2.7 升级到 3.5.16 + Java 17,开工前以为换个版本号就行,结果踩了一串坑:javax 全部变 jakarta、循环依赖启动直接报错、MyBatis-Plus 要换 starter、Knife4j 也要换 Jakarta 版。这篇是完整升级实录,照着避坑。
qkl-boot 从 Spring Boot 2.7 升到 3.5:javax 没了、循环依赖禁了、MyBatis-Plus 也得换版本
先说背景。qkl-boot 原本基于 Spring Boot 2.7 + Java 8,这次要整体升级到 Spring Boot 3.5.16 + Java 17(JDK 21 也能跑)。升级完跑起来用了整整一天,全是版本兼容问题。
第一步:pom 换依赖,三个坑排队等着
Spring Boot 3 的依赖坐标变化是第一个大坑。直接看现在的 pom:
17 3.5.16 org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import注意 Spring Boot 3 起,很多 starter 的包名和坐标都变了:
com.baomidou mybatis-plus-spring-boot3-starter com.github.xiaoymin knife4j-openapi3-jakarta-spring-boot-starter我一开始没换 MyBatis-Plus starter,启动报NoSuchBeanDefinitionException: SqlSessionFactory,排查半天才发现是坐标不对。老坐标mybatis-plus-boot-starter在 Boot 3 下不认。
第二步:javax 全部换 jakarta,全局替换别漏
Spring Boot 3 把 JavaEE 换成 Jakarta EE,javax.*全部变jakarta.*。代码里的 import 要全局替换:
// 升级前(javax)importjavax.annotation.Resource;importjavax.validation.constraints.NotBlank;importjavax.servlet.http.HttpServletRequest;// 升级后(jakarta)importjakarta.annotation.Resource;importjakarta.validation.constraints.NotBlank;importjakarta.servlet.http.HttpServletRequest;注意javax.annotation.Resource换成了jakarta.annotation.Resource,这个最容易漏,因为 IDE 不报编译错也能跑(启动时才报NoSuchBeanDefinitionException,排查很费劲)。建议全局搜索javax.逐个确认。
第三步:循环依赖,Boot 2.6+ 默认直接禁止
升级后启动报错,日志片段:
The dependencies of some of the beans in the application context form a cycle: ┌─────┐ | jobService ↑ ↓ | resumeService └─────┘Spring Boot 2.6 起默认禁止循环依赖,老项目两个 Service 互相注入的写法直接启动失败。
排查过程:找到互相依赖的两个类,jobService注入resumeService,resumeService又注入jobService。
定位思路:循环依赖是设计问题,别用spring.main.allow-circular-references=true强行放开,那是把问题埋起来。
最终解决:拆解依赖方向,只保留单向调用:
@ServicepublicclassResumeService{// 只注入 JobService,JobService 不再注入回来@ResourceprivateJobServicejobService;}把互相调用的公共逻辑抽到独立 Service 或者用事件驱动,循环引用从根上拆掉。
第四步:配置类和拦截器,包路径全变了
WebMvcConfigurerAdapter在 Boot 3 里改名WebMvcConfigurer(其实 2.x 就废了,但升级时容易踩),拦截器注册也变了:
@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(newTokenInterceptor()).addPathPatterns("/api/**").excludePathPatterns("/api/auth/login","/api/auth/register");}}同时spring.factories自动装配机制在 Boot 3 里被AutoConfiguration.imports文件取代,自定义 starter 的配置类要挪位置:
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports com.qkl.boot.autoconfigure.QklAutoConfiguration这个文件放错位置,自定义 starter 静默失效,没有任何报错,接口全都 404,排查起来非常阴间。
踩坑:Redis 客户端从 Jedis 变 Lettuce,连接池配置失效
现象:升级后 Redis 连接一直报Unable to connect to Redis,配置里明明写了连接池。
排查过程:Boot 3 默认用 Lettuce,我把spring.redis.jedis.pool.*的配置留着,Jedis 相关的配置项全部失效。
定位思路:看 Boot 3 文档,spring.data.redis.lettuce.pool.*才是 Lettuce 的配置前缀。
最终解决:
spring:data:redis:host:127.0.0.1port:6379lettuce:pool:max-active:16max-idle:8min-idle:2Spring Boot 3 的配置前缀从spring.redis变成了spring.data.redis,这个改动也容易漏,配置不生效但不报错。
可直接复用的要点
- Spring Boot 3 的javax→jakarta 全局替换,
javax.annotation.Resource最容易漏,启动才报错。 - MyBatis-Plus 必须用
mybatis-plus-spring-boot3-starter,Knife4j 用knife4j-openapi3-jakarta-spring-boot-starter。 - 循环依赖 Boot 2.6+ 默认禁止,拆解依赖方向,别开
allow-circular-references。 spring.factories换成AutoConfiguration.imports,放错位置自定义 starter 静默失效。- Redis 配置前缀变成
spring.data.redis,客户端默认 Lettuce。 - 升级后挨个模块启动验证,别一次性跳大版本,2.7→3.0→3.5 分步走更稳。
项目源码:https://gitee.com/gzqkl/qkl-boot