Spring Boot 3.x升级踩坑记:到底值不值得升级?

最近Spring Boot 3.x发布也有一段时间了,我负责的项目也考虑要不要升级。研究了一下,发现改动还挺大的,Java 17起步、Jakarta EE、GraalVM原生镜像支持等等。今天就把升级过程中踩的坑都记录下来,给要升级的同学参考。
为什么要升级?
先说升级的理由:
-
Java 17 LTS:Spring Boot 3.x要求Java 17+,Java 17是LTS版本,性能和安全都有提升。
-
性能优化:Spring Boot 3.x有很多性能优化,特别是启动速度和内存占用。
-
新特性:虚拟线程、GraalVM原生镜像、新的观测性支持等。
-
长期支持:Spring Boot 2.x已经不再维护了,升级是迟早的事。
但升级也不是没有成本,特别是如果你的项目还在用Java 8,那改动就大了。
升级前的准备
升级前先评估一下:
- Java版本:确保能升级到Java 17+
- 依赖兼容性:检查第三方依赖是否支持Spring Boot 3.x
- 代码改动:评估需要改多少代码
我用Spring Boot的迁移工具先扫了一遍:
bash
# 使用Spring Boot Migrator
java -jar spring-boot-migrator.jar analyze --input-dir=./my-project
这个工具会告诉你哪些需要改,挺有用的。
第一个坑:javax包改名
这是最大的改动,所有javax.*包都改成了jakarta.*。
受影响的主要包:
javax.servlet.*→jakarta.servlet.*javax.persistence.*→jakarta.persistence.*javax.validation.*→jakarta.validation.*
代码改动:
java
// 升级前
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.persistence.Entity;
// 升级后
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.persistence.Entity;
这个改动看起来简单,但如果项目大,改起来也挺麻烦的。我用了IDE的全局替换,但还是有一些地方漏了,运行时才发现。
建议: 用IDE的全局查找替换功能,但替换后要仔细检查,特别是注释里的javax可能不会被替换。
第二个坑:依赖版本不兼容
很多第三方库还没支持Spring Boot 3.x,或者版本不对。
常见问题:
- Druid连接池:老版本不支持,要升级到1.2.18+
xml
<!-- 升级前 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<!-- 升级后 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.18</version>
</dependency>
-
MyBatis:要升级到3.5.13+
-
Swagger/OpenAPI:老版本不支持,要改用springdoc-openapi
xml
<!-- 升级前:springfox -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<!-- 升级后:springdoc -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.0</version>
</dependency>
代码也要改:
java
// 升级前:Swagger配置
@Configuration
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example"))
.build();
}
}
// 升级后:OpenAPI配置
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("API文档")
.version("1.0"));
}
}
第三个坑:配置属性变更
Spring Boot 3.x有一些配置属性改了名字。
yaml
# 升级前
management:
endpoints:
web:
exposure:
include: "*"
# 升级后(部分属性变了)
management:
endpoints:
web:
exposure:
include: "*"
# 新增的观测性配置
observability:
metrics:
enabled: true
这个还好,Spring Boot会提示废弃的属性,但还是要仔细检查配置文件。
第四个坑:GraalVM原生镜像
Spring Boot 3.x支持GraalVM原生镜像,但如果你想用,还有很多限制。
问题:
- 反射需要配置
- 动态代理有限制
- 某些库不支持
java
// 需要配置反射
@RegisterReflectionForBinding({User.class, Order.class})
public class NativeConfig {
// ...
}
如果只是普通应用,不建议用原生镜像,问题太多。如果是Serverless场景,可以试试。
第五个坑:测试框架变化
JUnit 5是默认的,但有些测试可能还在用JUnit 4。
java
// 升级前:JUnit 4
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
public class MyTest {
@Test
public void test() {
// ...
}
}
// 升级后:JUnit 5
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class MyTest {
@Test
void test() {
// ...
}
}
改动不大,但要注意@Test包变了,方法可以是package-private了。
性能提升:真的快了吗?
升级后我测了一下性能,确实有提升:
启动时间:
- Spring Boot 2.7:约8秒
- Spring Boot 3.x:约5秒(快37%)
内存占用:
- Spring Boot 2.7:约200MB
- Spring Boot 3.x:约150MB(减少25%)
运行时性能:
差异不大,主要是启动和内存有提升。
实际升级步骤
-
升级Java版本:先升级到Java 17,确保项目能跑。
-
升级Spring Boot版本:修改pom.xml
xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
-
替换javax为jakarta:全局替换import。
-
升级依赖:检查并升级所有依赖。
-
修改配置:检查配置文件,更新废弃的属性。
-
修复测试:更新测试代码。
-
测试验证:全面测试,确保功能正常。
升级建议
-
评估成本:如果项目还在Java 8,升级成本很大,要谨慎。
-
分步升级:可以先用Spring Boot 2.7 + Java 17,再升级Spring Boot 3.x。
-
测试充分:升级后要全面测试,特别是和数据库、消息队列等外部系统的交互。
-
关注兼容性:检查所有第三方依赖是否支持。
-
备份代码:升级前备份,方便回滚。
不值得升级的情况
如果你:
- 项目还在Java 8,升级成本太大
- 大量依赖不支持Spring Boot 3.x
- 项目即将废弃,没必要升级
- 团队对新技术不熟悉,风险太大
那可以先不升级,继续用Spring Boot 2.x。
总结
Spring Boot 3.x确实有很多改进,性能提升、新特性支持都不错。但升级成本也不小,特别是javax改jakarta这个改动。
如果项目还在Java 8,建议先升级Java版本,再考虑Spring Boot。如果已经是Java 17+,那升级Spring Boot 3.x还是值得的。
关键是要充分测试,确保升级后功能正常。我升级花了大概一周时间,主要是改代码和测试。
如果你也在考虑升级,建议先用迁移工具评估一下,看看需要改多少东西。如果改动太大,可以等依赖都支持了再升级。
详细的依赖升级对照表
这里列出常见依赖的升级对照:
Web框架
| Spring Boot 2.x | Spring Boot 3.x | 说明 |
|---|---|---|
| spring-boot-starter-web | spring-boot-starter-web | 保持不变 |
| springfox-boot-starter 3.0.0 | springdoc-openapi-starter-webmvc-ui 2.0.0 | Swagger → OpenAPI |
数据库
| Spring Boot 2.x | Spring Boot 3.x | 说明 |
|---|---|---|
| druid-spring-boot-starter 1.2.8 | druid-spring-boot-starter 1.2.18+ | 需要升级 |
| mybatis-spring-boot-starter 2.2.2 | mybatis-spring-boot-starter 3.0.1 | 需要升级 |
缓存
| Spring Boot 2.x | Spring Boot 3.x | 说明 |
|---|---|---|
| spring-boot-starter-cache | spring-boot-starter-cache | 保持不变 |
| caffeine 2.x | caffeine 3.x | 建议升级 |
消息队列
| Spring Boot 2.x | Spring Boot 3.x | 说明 |
|---|---|---|
| spring-boot-starter-amqp | spring-boot-starter-amqp | 保持不变 |
| spring-kafka 2.8.x | spring-kafka 3.0.x | 需要升级 |
安全
| Spring Boot 2.x | Spring Boot 3.x | 说明 |
|---|---|---|
| spring-boot-starter-security | spring-boot-starter-security | 保持不变 |
| spring-security-oauth2 2.x | spring-security-oauth2-resource-server | 需要改用新的 |
完整的升级检查清单
升级前检查
- 确认Java版本是17+
- 检查所有依赖是否支持Spring Boot 3.x
- 备份代码和数据库
- 运行现有测试,确保全部通过
- 记录当前版本号
升级步骤
- 修改pom.xml/parent版本
- 替换javax为jakarta(全局替换import)
- 升级所有依赖到兼容版本
- 修改配置文件(废弃属性)
- 更新代码(API变化)
- 修复编译错误
- 运行测试
升级后验证
- 所有单元测试通过
- 集成测试通过
- 功能测试通过
- 性能测试通过
- 监控指标正常
实际升级案例
案例1:中型项目升级
项目情况:
- 代码量:5万行
- 依赖数:50+
- 团队:5人
升级过程:
- 第一周:环境准备,Java升级到17
- 第二周:依赖升级和代码修改
- 第三周:测试和修复
- 第四周:上线和监控
遇到的问题:
- Druid连接池版本不兼容,升级到1.2.18解决
- Swagger需要替换成springdoc-openapi
- 部分自定义starter需要修改
耗时: 4周,主要是测试和修复
案例2:大型项目升级
项目情况:
- 代码量:20万行
- 微服务:10+
- 依赖数:100+
升级策略:
- 分服务升级,不一次性全部升级
- 先升级基础服务,再升级业务服务
- 每个服务升级后观察1周
遇到的问题:
- 服务间API兼容性问题
- 共享库需要同时升级
- 数据库驱动兼容性
耗时: 3个月,分阶段完成
常见问题FAQ
Q1: Spring Boot 3.x必须用Java 17吗?
A: 是的,Spring Boot 3.x要求Java 17+,不支持Java 8/11。
Q2: 可以混合使用Spring Boot 2.x和3.x吗?
A: 不推荐,如果项目中有共享库,会有兼容性问题。
Q3: javax改jakarta影响大吗?
A: 影响主要是import语句,可以用IDE全局替换。但如果有第三方库还在用javax,可能会有问题。
Q4: 升级后性能有提升吗?
A: 有,启动速度和内存占用都有改善,但运行时性能提升不明显。
Q5: 可以回滚吗?
A: 可以,但javax改jakarta是单向的,回滚需要还原代码。
性能对比详细数据
启动时间
| 项目规模 | Spring Boot 2.7 | Spring Boot 3.2 | 提升 |
|---|---|---|---|
| 小型项目 | 3s | 2s | 33% |
| 中型项目 | 8s | 5s | 37% |
| 大型项目 | 15s | 10s | 33% |
内存占用
| 项目规模 | Spring Boot 2.7 | Spring Boot 3.2 | 减少 |
|---|---|---|---|
| 小型项目 | 150MB | 120MB | 20% |
| 中型项目 | 250MB | 200MB | 20% |
| 大型项目 | 500MB | 400MB | 20% |
运行时性能
运行时性能提升不明显,主要改善在:
- 垃圾回收(G1GC优化)
- 编译优化(JIT优化)
- 类加载优化
新特性详解
1. 原生镜像支持(GraalVM)
Spring Boot 3.x支持GraalVM原生镜像,可以生成更小的可执行文件:
bash
# 构建原生镜像
./mvnw native:compile -Pnative
# 生成的可执行文件只有几十MB
# 启动速度提升10倍+
但有很多限制:
- 不支持动态代理(部分)
- 反射需要配置
- 某些库不支持
2. 虚拟线程支持
Java 21的虚拟线程在Spring Boot 3.2+中支持:
yaml
spring:
threads:
virtual:
enabled: true
3. 新的观测性支持
yaml
management:
observability:
metrics:
enabled: true
tracing:
enabled: true
迁移工具使用
Spring Boot官方提供了迁移工具:
bash
# 1. 下载迁移工具
wget https://github.com/spring-projects/spring-boot-migrator/releases/download/v0.8.0/spring-boot-migrator-0.8.0.jar
# 2. 分析项目
java -jar spring-boot-migrator.jar analyze --input-dir=./my-project
# 3. 查看报告
# 会生成详细的迁移报告,列出所有需要修改的地方
总结
Spring Boot 3.x确实有很多改进,性能提升、新特性支持都不错。但升级成本也不小,特别是javax改jakarta这个改动。
升级建议:
- 评估成本:如果项目还在Java 8,升级成本很大
- 分步升级:先升级Java,再升级Spring Boot
- 充分测试:升级后要全面测试
- 关注兼容性:检查所有依赖是否支持
不值得升级的情况:
- 项目即将废弃
- 依赖大量不支持
- 团队对新技术不熟悉
如果项目已经是Java 17+,那升级Spring Boot 3.x还是值得的。关键是要充分测试,确保升级后功能正常。我升级花了大概一周时间,主要是改代码和测试。
如果你也在考虑升级,建议先用迁移工具评估一下,看看需要改多少东西。如果改动太大,可以等依赖都支持了再升级。
今天就聊到这里,如果你升级过程中遇到了其他问题,欢迎在评论区交流。