Spring Boot 3.x迁移指南:从2.x升级的完整流程和坑点总结
今年初公司要把所有SpringBoot应用升级到3.x(主要是要用虚拟线程和Native Image),我负责迁移工作。整个过程踩了不少坑,这篇文章分享完整的迁移流程和解决方案。
为什么要升级到Spring Boot 3.x?
先说结论:Spring Boot 3.x不是简单的版本升级,而是一次架构升级。
核心变化:
- Java 17+:Spring Boot 3.x要求Java 17+(Spring Boot 2.x支持Java 8+)
- Jakarta EE 9+:包名从
javax.*改为jakarta.*(这个改动最大) - Spring Framework 6.x:底层框架升级
- GraalVM Native Image支持:可以把应用编译成原生可执行文件
- 虚拟线程支持:Spring Boot 3.2+支持Java 21虚拟线程
如果不升级会怎样?
- Spring Boot 2.x到2025年底就EOL(End of Life)了
- 新特性(虚拟线程、Native Image)用不了
- 安全漏洞没人修
迁移前的准备工作
1. 评估影响范围
检查清单:
- 项目用的Java版本(如果是Java 8,要先升级到Java 17)
- 项目依赖的第三方库(是否支持Spring Boot 3.x)
- 项目用的
javax.*包(要改为jakarta.*) - 项目用的Spring Cloud版本(要升级到2022.0.0+)
工具推荐:
- Spring Boot Migrator:自动扫描项目,给出迁移建议
- OpenRewrite:自动重构代码(比如把
javax.*改为jakarta.*)
2. 搭建迁移环境
建议:
- 创建新的Git分支(比如
migrate-to-springboot-3.x) - 在测试环境先做迁移,不要直接改生产代码
- 准备好回滚方案
迁移步骤(详细版)
步骤1:升级Java版本
如果项目用的是Java 8或Java 11,要先升级到Java 17+。
方式1:用SDKMAN管理多版本Java
# 安装SDKMAN
curl -s "https://get.sdkman.io" | bash
# 安装Java 17
sdk install java 17.0.1-tem
# 切换到Java 17
sdk use java 17.0.1-tem
方式2:直接下载JDK
- 访问Adoptium,下载JDK 17
- 设置
JAVA_HOME环境变量
验证:
java -version
# 输出应该包含 "17.0.x"
步骤2:修改pom.xml
修改Spring Boot版本:
<!-- 修改前 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>
<!-- 修改后 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
修改Spring Cloud版本(如果用了Spring Cloud):
<!-- 修改前 -->
<properties>
<spring-cloud.version>2021.0.8</spring-cloud.version>
</properties>
<!-- 修改后 -->
<properties>
<spring-cloud.version>2023.0.0</spring-cloud.version>
</properties>
步骤3:替换javax.*为jakarta.*
这是最麻烦的一步。
需要修改的包:
| 修改前 | 修改后 |
|---|---|
javax.servlet.* | jakarta.servlet.* |
javax.persistence.* | jakarta.persistence.* |
javax.validation.* | jakarta.validation.* |
javax.annotation.* | jakarta.annotation.* |
示例:
// 修改前
import javax.servlet.http.HttpServletRequest;
@RestController
public class TestController {
@GetMapping("/test")
public String test(HttpServletRequest request) {
return "Hello";
}
}
// 修改后
import jakarta.servlet.http.HttpServletRequest;
@RestController
public class TestController {
@GetMapping("/test")
public String test(HttpServletRequest request) {
return "Hello";
}
}
自动化工具:
用OpenRewrite可以自动完成这个替换:
# 1. 添加OpenRewrite插件到pom.xml
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.31.0</version>
<configuration>
<activeRecipes>
<recipe>org.openrewrite.java.migrate.JavaxToJakarta</recipe>
</activeRecipes>
</configuration>
</plugin>
# 2. 运行重构
mvn rewrite:run
步骤4:升级第三方依赖
常见问题:有些第三方库不支持Spring Boot 3.x,需要升级版本。
示例:MyBatis
<!-- 修改前 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<!-- 修改后 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
常见依赖的兼容版本:
| 依赖 | Spring Boot 2.x版本 | Spring Boot 3.x版本 |
|---|---|---|
| MyBatis | 2.3.x | 3.0.x |
| Druid | 1.2.x | 1.2.20+ |
| Swagger | springfox 3.0.0 | springdoc-openapi 2.3.0 |
| Redis | lettuce 6.x | lettuce 6.2+ |
步骤5:修改配置文件
Spring Boot 3.x对一些配置项做了重命名。
示例:
# 修改前(Spring Boot 2.x)
spring:
mvc:
throw-exception-if-no-handler-found: true
resources:
add-mappings: false
# 修改后(Spring Boot 3.x)
spring:
mvc:
throw-exception-if-no-handler-found: true
web:
resources:
add-mappings: false
完整的配置变更列表:参考Spring Boot 3.0 Migration Guide
步骤6:编译和测试
# 1. 编译
mvn clean compile
# 2. 运行测试
mvn test
# 3. 启动应用
mvn spring-boot:run
如果编译报错,根据错误信息逐个修复(大部分是javax.*没改干净)。
如果启动报错,查看日志,常见问题:
- 配置项改名了 → 参考Migration Guide
- 依赖版本不兼容 → 升级依赖
- 反射权限问题(如果用了Native Image)→ 添加
@RegisterForReflection注解
常见坑点和解决方案
坑1:Swagger不兼容
问题:Spring Boot 3.x不支持Springfox(Swagger 2),要改用Springdoc OpenAPI。
解决方案:
<!-- 移除Springfox -->
<!--
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
-->
<!-- 添加Springdoc OpenAPI -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency>
代码改动:
// 修改前(Springfox注解)
@Api(tags = "用户管理")
@RestController
public class UserController {
@ApiOperation("获取用户")
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
return userService.getById(id);
}
}
// 修改后(Springdoc注解)
@Tag(name = "用户管理")
@RestController
public class UserController {
@Operation(summary = "获取用户")
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
return userService.getById(id);
}
}
坑2:Druid数据源不兼容
问题:Druid 1.2.8以下版本不支持Spring Boot 3.x。
解决方案:升级到Druid 1.2.20+。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.20</version>
</dependency>
坑3:Reflection权限问题(Native Image)
问题:如果用了Native Image,反射调用会报错。
解决方案:在reflect-config.json中注册需要反射的类(参考我之前写的GraalVM文章)。
坑4:JUnit测试不兼容
问题:Spring Boot 3.x用JUnit 5,如果项目用的是JUnit 4,要改。
解决方案:
// 修改前(JUnit 4)
import org.junit.Test;
public class UserServiceTest {
@Test
public void testGetUser() {
// ...
}
}
// 修改后(JUnit 5)
import org.junit.jupiter.api.Test;
public class UserServiceTest {
@Test
void testGetUser() {
// ...
}
}
自动化工具:用OpenRewrite可以自动完成这个替换。
迁移后的验证清单
- 应用能正常启动
- 所有单元测试通过
- 所有API接口正常(用Postman或JMeter测试)
- 数据库操作正常
- 缓存(Redis)操作正常
- 消息队列(MQ)操作正常
- 日志输出正常
- 健康检查接口正常(
/actuator/health) - 性能指标正常(用JMeter压测)
总结
Spring Boot 3.x迁移工作量不小,但这是必须做的。我的建议:
- 新项目:直接用Spring Boot 3.2 + Java 21(一步到位)
- 老项目:制定迁移计划,逐步迁移(先迁移不重要的服务)
- 测试优先:迁移完后一定要做充分的测试(单元测试 + 集成测试 + 压测)
- 工具辅助:用Spring Boot Migrator和OpenRewrite自动化迁移,减少手动改代码的工作量
最后说一句:迁移虽然麻烦,但迁移后能用上虚拟线程、Native Image这些新特性,还是很值得的。
参考资料:

1170

被折叠的 条评论
为什么被折叠?



