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 准备阶段
- 冻结功能需求,建立迁移专项分支;
- 搭建与生产环境一致的测试环境;
- 编写自动化回归测试用例,覆盖核心业务链路;
- 记录当前依赖版本清单,作为回滚基线。
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」的两步走策略,配合自动化测试与灰度发布,将风险控制在可接受范围内。迁移完成后,你将获得更长的社区支持周期、更强的安全性与更现代的编程体验。