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

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

最近Spring Boot 3.x发布也有一段时间了,我负责的项目也考虑要不要升级。研究了一下,发现改动还挺大的,Java 17起步、Jakarta EE、GraalVM原生镜像支持等等。今天就把升级过程中踩的坑都记录下来,给要升级的同学参考。

为什么要升级?

先说升级的理由:

  1. Java 17 LTS:Spring Boot 3.x要求Java 17+,Java 17是LTS版本,性能和安全都有提升。

  2. 性能优化:Spring Boot 3.x有很多性能优化,特别是启动速度和内存占用。

  3. 新特性:虚拟线程、GraalVM原生镜像、新的观测性支持等。

  4. 长期支持:Spring Boot 2.x已经不再维护了,升级是迟早的事。

但升级也不是没有成本,特别是如果你的项目还在用Java 8,那改动就大了。

升级前的准备

升级前先评估一下:

  1. Java版本:确保能升级到Java 17+
  2. 依赖兼容性:检查第三方依赖是否支持Spring Boot 3.x
  3. 代码改动:评估需要改多少代码

我用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,或者版本不对。

常见问题:

  1. 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>
  1. MyBatis:要升级到3.5.13+

  2. 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原生镜像,但如果你想用,还有很多限制。

问题:

  1. 反射需要配置
  2. 动态代理有限制
  3. 某些库不支持
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%)

运行时性能:

差异不大,主要是启动和内存有提升。

实际升级步骤

  1. 升级Java版本:先升级到Java 17,确保项目能跑。

  2. 升级Spring Boot版本:修改pom.xml

xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.0</version>
</parent>
  1. 替换javax为jakarta:全局替换import。

  2. 升级依赖:检查并升级所有依赖。

  3. 修改配置:检查配置文件,更新废弃的属性。

  4. 修复测试:更新测试代码。

  5. 测试验证:全面测试,确保功能正常。

升级建议

  1. 评估成本:如果项目还在Java 8,升级成本很大,要谨慎。

  2. 分步升级:可以先用Spring Boot 2.7 + Java 17,再升级Spring Boot 3.x。

  3. 测试充分:升级后要全面测试,特别是和数据库、消息队列等外部系统的交互。

  4. 关注兼容性:检查所有第三方依赖是否支持。

  5. 备份代码:升级前备份,方便回滚。

不值得升级的情况

如果你:

  • 项目还在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人

升级过程:

  1. 第一周:环境准备,Java升级到17
  2. 第二周:依赖升级和代码修改
  3. 第三周:测试和修复
  4. 第四周:上线和监控

遇到的问题:

  1. Druid连接池版本不兼容,升级到1.2.18解决
  2. Swagger需要替换成springdoc-openapi
  3. 部分自定义starter需要修改

耗时: 4周,主要是测试和修复

案例2:大型项目升级

项目情况:

  • 代码量:20万行
  • 微服务:10+
  • 依赖数:100+

升级策略:

  1. 分服务升级,不一次性全部升级
  2. 先升级基础服务,再升级业务服务
  3. 每个服务升级后观察1周

遇到的问题:

  1. 服务间API兼容性问题
  2. 共享库需要同时升级
  3. 数据库驱动兼容性

耗时: 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这个改动。

升级建议:

  1. 评估成本:如果项目还在Java 8,升级成本很大
  2. 分步升级:先升级Java,再升级Spring Boot
  3. 充分测试:升级后要全面测试
  4. 关注兼容性:检查所有依赖是否支持

不值得升级的情况:

  • 项目即将废弃
  • 依赖大量不支持
  • 团队对新技术不熟悉

如果项目已经是Java 17+,那升级Spring Boot 3.x还是值得的。关键是要充分测试,确保升级后功能正常。我升级花了大概一周时间,主要是改代码和测试。

如果你也在考虑升级,建议先用迁移工具评估一下,看看需要改多少东西。如果改动太大,可以等依赖都支持了再升级。

今天就聊到这里,如果你升级过程中遇到了其他问题,欢迎在评论区交流。

相关推荐
Java编程爱好者2 小时前
JDK 21 中的虚拟线程:革新 Java 多线程
后端
悟能不能悟2 小时前
springboot controller返回的是HttpServletResponse成功返回excel文件流,失败就返回失败参数
spring boot·后端·excel
神奇小汤圆2 小时前
面试官:如何在 Kafka 中实现延迟消息?
后端
李慕婉学姐2 小时前
【开题答辩过程】以《智慧校园创新互助小程序的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·spring boot·小程序
请告诉他2 小时前
【实战经验】Dell Inspiron 7560 升级 BIOS 支持 DDR4-2666 内存,解决 Spring Cloud 多模块开发内存瓶颈
后端·spring·spring cloud
我想问问天2 小时前
【从0到1大模型应用开发实战】02|用 LangChain 和本地大模型,完成第一次“可控对话
后端·langchain·aigc
爱吃牛肉的大老虎2 小时前
Spring WebFlux与SpringMVC 对比讲解
java·后端·spring
老华带你飞3 小时前
房屋租赁管理系统|基于java+ vue房屋租赁管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端