Spring Boot 2.1 → 3.5 迁移推演:从实战出发的完整路线图

1. 引言

Spring Boot 2.1 发布于 2018 年,至今已走过多个大版本。随着 Spring Boot 3.5 的发布,许多老项目正面临一次「不得不做」的升级。本文不打算罗列官方文档,而是从一次真实迁移推演出发,梳理从 2.1 到 3.5 的关键路径、踩坑点与决策依据,帮助你在动手前建立全局认知。

2. 迁移全景:从 2.1 到 3.5 要跨过哪些坎

先看整体路线。Spring Boot 2.1 → 3.5 并非一步到位,中间隔着 2.x 系列、3.0、3.1、3.2、3.3、3.4 等多个里程碑。建议按「两步走」推进:
#mermaid-svg-KScWOsL4lq1tWUAr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KScWOsL4lq1tWUAr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KScWOsL4lq1tWUAr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KScWOsL4lq1tWUAr .error-icon{fill:#552222;}#mermaid-svg-KScWOsL4lq1tWUAr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KScWOsL4lq1tWUAr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KScWOsL4lq1tWUAr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KScWOsL4lq1tWUAr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KScWOsL4lq1tWUAr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KScWOsL4lq1tWUAr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KScWOsL4lq1tWUAr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KScWOsL4lq1tWUAr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KScWOsL4lq1tWUAr .marker.cross{stroke:#333333;}#mermaid-svg-KScWOsL4lq1tWUAr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KScWOsL4lq1tWUAr p{margin:0;}#mermaid-svg-KScWOsL4lq1tWUAr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KScWOsL4lq1tWUAr .cluster-label text{fill:#333;}#mermaid-svg-KScWOsL4lq1tWUAr .cluster-label span{color:#333;}#mermaid-svg-KScWOsL4lq1tWUAr .cluster-label span p{background-color:transparent;}#mermaid-svg-KScWOsL4lq1tWUAr .label text,#mermaid-svg-KScWOsL4lq1tWUAr span{fill:#333;color:#333;}#mermaid-svg-KScWOsL4lq1tWUAr .node rect,#mermaid-svg-KScWOsL4lq1tWUAr .node circle,#mermaid-svg-KScWOsL4lq1tWUAr .node ellipse,#mermaid-svg-KScWOsL4lq1tWUAr .node polygon,#mermaid-svg-KScWOsL4lq1tWUAr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KScWOsL4lq1tWUAr .rough-node .label text,#mermaid-svg-KScWOsL4lq1tWUAr .node .label text,#mermaid-svg-KScWOsL4lq1tWUAr .image-shape .label,#mermaid-svg-KScWOsL4lq1tWUAr .icon-shape .label{text-anchor:middle;}#mermaid-svg-KScWOsL4lq1tWUAr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KScWOsL4lq1tWUAr .rough-node .label,#mermaid-svg-KScWOsL4lq1tWUAr .node .label,#mermaid-svg-KScWOsL4lq1tWUAr .image-shape .label,#mermaid-svg-KScWOsL4lq1tWUAr .icon-shape .label{text-align:center;}#mermaid-svg-KScWOsL4lq1tWUAr .node.clickable{cursor:pointer;}#mermaid-svg-KScWOsL4lq1tWUAr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KScWOsL4lq1tWUAr .arrowheadPath{fill:#333333;}#mermaid-svg-KScWOsL4lq1tWUAr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KScWOsL4lq1tWUAr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KScWOsL4lq1tWUAr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KScWOsL4lq1tWUAr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KScWOsL4lq1tWUAr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KScWOsL4lq1tWUAr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KScWOsL4lq1tWUAr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KScWOsL4lq1tWUAr .cluster text{fill:#333;}#mermaid-svg-KScWOsL4lq1tWUAr .cluster span{color:#333;}#mermaid-svg-KScWOsL4lq1tWUAr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KScWOsL4lq1tWUAr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KScWOsL4lq1tWUAr rect.text{fill:none;stroke-width:0;}#mermaid-svg-KScWOsL4lq1tWUAr .icon-shape,#mermaid-svg-KScWOsL4lq1tWUAr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KScWOsL4lq1tWUAr .icon-shape p,#mermaid-svg-KScWOsL4lq1tWUAr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KScWOsL4lq1tWUAr .icon-shape .label rect,#mermaid-svg-KScWOsL4lq1tWUAr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KScWOsL4lq1tWUAr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KScWOsL4lq1tWUAr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KScWOsL4lq1tWUAr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Spring Boot 2.1
Spring Boot 2.7(2.x 终点站)
Spring Boot 3.0(Jakarta EE 9+ 切换)
Spring Boot 3.5(当前最新稳定版)

  • 第一步:先升到 2.7,这是 2.x 系列的最后一个版本,兼容性最好,适合先消化 2.x 内部的废弃 API。
  • 第二步:从 2.7 直接跳到 3.5。3.0 是破坏性最大的版本,但 3.5 已吸收大量修复,直接跨版本反而能少走弯路。

3. 核心破坏性变更盘点

3.1 Jakarta EE 命名空间切换

这是 2.x → 3.x 最根本的变化:javax.* 全面迁移到 jakarta.*。

java 复制代码
// 迁移前(Spring Boot 2.x)
import javax.servlet.http.HttpServletRequest;
import javax.persistence.Entity;

// 迁移后(Spring Boot 3.x)
import jakarta.servlet.http.HttpServletRequest;
import jakarta.persistence.Entity;

影响面包括 Servlet、JPA、Validation、Mail 等几乎所有 Java EE 规范。IDE 的全局替换功能可以大幅降低工作量,但要注意不要误替换 javax.annotation 中仍保留的注解(如 @Resource 在 Jakarta 中也有对应版本,需按依赖判断)。

3.2 Java 版本基线提升

Spring Boot 3.x 强制要求 Java 17+,这意味着:

  • 如果你的项目还在 Java 8,需要先完成 JDK 升级;
  • 建议直接上 Java 21(LTS),配合 Spring Boot 3.5 体验最佳;
  • 升级 JDK 时注意 Lombok、MapStruct 等注解处理器版本是否兼容。

3.3 Spring Security 6 的配置方式变化

Spring Security 5 → 6 是一次大重构,WebSecurityConfigurerAdapter 被彻底移除,改为基于 SecurityFilterChain 的 Bean 声明式配置:

java 复制代码
// Spring Boot 2.x 旧写法
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/public/**").permitAll()
            .anyRequest().authenticated();
    }
}

// Spring Boot 3.x 新写法
@Configuration
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth
            .requestMatchers("/public/**").permitAll()
            .anyRequest().authenticated());
        return http.build();
    }
}

注意 antMatchers 已废弃,改用 requestMatchers;authorizeRequests 改为 authorizeHttpRequests。

3.4 配置属性迁移

Spring Boot 3.x 对大量配置属性做了重命名或移除。常见的有:

旧配置(2.x) 新配置(3.x)
server.servlet.session.timeout server.servlet.session.timeout(语义微调)
spring.datasource.hikari.connection-timeout spring.datasource.hikari.connection-timeout(保留)
spring.redis.* 部分迁移到 spring.data.redis.*
spring.mvc.throw-exception-if-no-handler-found 移除,改用自定义配置

建议在升级后用 spring-boot-properties-migrator 依赖辅助检测:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-properties-migrator</artifactId>
    <scope>runtime</scope>
</dependency>

启动时它会打印所有需要迁移的属性警告,非常实用。

4. 依赖与第三方库兼容性排查

这是迁移中最耗时的一环。重点检查以下几类:

  • MyBatis / MyBatis-Plus:确认版本支持 Jakarta 命名空间;
  • Redis 客户端:Lettuce 在 3.x 下表现稳定,Jedis 需确认版本;
  • 消息队列:如 RocketMQ、RabbitMQ 的 Spring Boot starter 是否已适配 3.x;
  • 分布式框架:如 Dubbo、Seata,需逐一核对官方兼容矩阵;
  • 定时任务:XXL-Job 等需确认对 Spring Boot 3 的支持。

建议维护一张「依赖兼容性清单」,逐项标记状态,避免遗漏。

5. 迁移执行步骤推演

5.1 准备阶段

  1. 冻结功能需求,建立迁移专项分支;
  2. 搭建与生产环境一致的测试环境;
  3. 编写自动化回归测试用例,覆盖核心业务链路;
  4. 记录当前依赖版本清单,作为回滚基线。

5.2 分步执行

bash 复制代码
# 第一步:升级到 2.7
# 修改 pom.xml 中的 parent 版本
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version>
</parent>

# 第二步:升级 JDK 到 17+
# 第三步:升级到 3.5
# 修改 parent 版本为 3.5.x

每完成一步都运行全量测试,确认无回归后再进入下一步。

5.3 常见报错速查

报错信息 原因 解决方案
ClassNotFoundException: javax.servlet.* 未完成 Jakarta 迁移 全局替换 javax → jakarta
NoSuchMethodError: WebSecurityConfigurerAdapter Security 配置未迁移 改用 SecurityFilterChain Bean
Invalid value type for attribute 'factoryBeanObjectType' MyBatis 版本过旧 升级 MyBatis 到适配 3.x 的版本
Caused by: java.lang.UnsupportedClassVersionError JDK 版本过低 升级到 Java 17+

6. 迁移后的验证与灰度

升级完成不代表结束,还需要:

  • 全量回归测试:重点验证登录鉴权、文件上传、定时任务、消息消费等链路;
  • 性能对比:对比迁移前后的接口响应时间、内存占用;
  • 灰度发布:先让 10% 流量走新版本,观察日志与监控指标;
  • 回滚预案:保留 2.1 版本的镜像与配置,确保可快速回退。

7. 总结

Spring Boot 2.1 → 3.5 的迁移是一次系统性工程,核心难点集中在 Jakarta 命名空间切换、Java 版本升级、Spring Security 重构和第三方依赖兼容四个方面。建议遵循「先 2.7、再 3.5」的两步走策略,配合自动化测试与灰度发布,将风险控制在可接受范围内。迁移完成后,你将获得更长的社区支持周期、更强的安全性与更现代的编程体验。

相关推荐
JPower_mr.g1 小时前
SmartCall 音色管理技术解析:基于 SPI 的可扩展音色注册架构
java·开发语言·人工智能·ai·架构·开源
测试开发Kevin1 小时前
IDEA工程结构解析:项目、模块、库、Facet、Artifact (工件) 概念说明
java·ide·intellij idea
Wang's Blog1 小时前
Java 中间件之 RabbitMQ 快速入门: SpringAMQP 的 DirectExchange 路由模式
java·中间件·java-rabbitmq
Sweet锦1 小时前
jDCS 开源项目:面向工业现场的 Modbus RTU 数据采集基础框架
java·spring boot·物联网·开源
海马2 小时前
Spring Boot 开发知识整理
java·spring boot·后端
xiaolinudao1232 小时前
将多个 Excel 表格中的数据合并到单个表中|6 种实现方案全解析
java·前端·excel
谢亮_vipxieliang2 小时前
Spring Boot 3.x 从零开始——环境搭建与第一个 REST 项目
java·spring boot·后端
念何架构之路2 小时前
go-grpc核心抽象接口
开发语言·后端·golang
Wang's Blog2 小时前
Java 项目部署之 Docker工具快速入门: Docker 架构拆解:镜像、容器、守护进程与 Registry
java·docker·架构