Spring Boot 2 升级到 Spring Boot 3 有哪些关键变化?
简化版
Spring Boot 3 的基础是 Java 17、Spring Framework 6 和 Jakarta EE 10,最明显的迁移是相关 API 从 javax.* 切换为 jakarta.*,并伴随依赖基线、配置属性和安全/JPA 等框架升级。它不是只改 Boot 版本号就能完成的升级,应先升到最新 2.7.x、清除弃用项,再逐项升级依赖、源码、配置和运行环境。
详细版
关键变化包括:最低 Java 版本提高到 17;Spring Framework 6 使用 Jakarta 命名空间;Servlet、Persistence、Validation 等 Jakarta EE API 包名变化;Hibernate、Spring Security 等主要依赖进入新大版本;AOT 与原生镜像支持进入核心能力,观测体系也进一步统一到 Micrometer Observation。
迁移时不能全局把所有 javax 替换成 jakarta,只有迁移到 Jakarta EE 的规范包需要修改,javax.crypto、javax.sql 等 Java SE 包仍保留原名。外部 Servlet 容器、第三方 Starter、字节码工具和测试库也必须选择兼容 Jakarta 的版本。
完整版教学
一、为什么是一次平台升级
Boot 3 不只是 Boot 自身换代,它同时提升了 JDK、Spring Framework 和 Jakarta EE 基线。应用源码、编译插件、运行镜像、容器、Agent 与第三方库都可能受到影响。
因此应先建立依赖清单和兼容矩阵,确认每个关键组件是否发布了 Boot 3/Spring 6 兼容版本。仅让主模块编译通过,不能证明运行时没有旧版 API 冲突。
二、Java 17 基线
编译和运行 Boot 3 应使用 Java 17 或更高的兼容版本。升级前要同步检查 CI、Docker 基础镜像、生产 JVM、Maven/Gradle Toolchain 和 IDE,避免本地用新 JDK、部署仍用旧 JRE。
Java 17 还意味着可以使用 Record、文本块和改进的语言/API,但升级目的首先是满足平台基线,不应把业务重构与框架迁移一次性混成无法回退的大变更。
三、javax 到 jakarta 的边界
// Boot 2 / Java EE 时代
import javax.persistence.Entity;
import javax.validation.constraints.NotBlank;
// Boot 3 / Jakarta EE 时代
import jakarta.persistence.Entity;
import jakarta.validation.constraints.NotBlank;
Servlet、JPA、Validation、Annotation 等规范已经迁到 jakarta 包名,使用这些 API 的代码、生成源码和第三方库都要兼容。部署 war 时,外部容器也必须支持对应 Jakarta Servlet 规范,旧 javax.servlet 容器不能加载新应用。
不要机械替换所有 javax。javax.sql.DataSource、javax.crypto.Cipher 等属于 Java SE,仍然使用 javax 包。
四、依赖与配置变化
Boot 管理的 Spring Security、Hibernate 等进入新大版本,可能带来 API、默认行为和配置方式变化。安全配置应迁向 SecurityFilterChain Bean 等当前组件式方式;Hibernate 6 的类型、查询和方言变化则需要通过真实数据库测试验证。
部分旧配置属性被重命名或删除。迁移期间可临时使用 spring-boot-properties-migrator 帮助诊断属性变化,但修复完成后应移除它,不能把运行期兼容提示当长期方案。
五、自动配置与第三方 Starter
Boot 3 的自定义自动配置使用 AutoConfiguration.imports 机制。第三方 Starter 若仍基于旧 Spring API、javax 类型或不兼容的自动配置条件,即使依赖能下载,也可能在启动时出现类不存在、方法不存在或条件失配。
应查看 Starter 官方兼容表,不要用排除传递依赖、强行覆盖 Spring Framework 版本的方式拼出未经验证的组合。内部 Starter 也要单独发布兼容 Boot 3 的大版本。
六、AOT、Native 与可观测性
Boot 3 把 AOT 处理和 GraalVM Native Image 支持纳入正式体系,但升级到 Boot 3 不等于应用自动变成原生镜像。反射、动态代理、资源和序列化仍可能需要 AOT 提示,构建与运行行为也要专项测试。
Micrometer Observation 为指标与链路观测提供更统一的抽象。若应用使用旧 Sleuth、Tracing 或自定义埋点,需要按目标 Boot 3 版本迁移到兼容方案,而不是继续混用旧依赖。
七、推荐迁移顺序
- 先升级到最新稳定的 2.7.x,处理所有弃用警告;
- 升级构建工具、插件、CI 和运行环境到 Java 17;
- 检查第三方依赖与内部 Starter 的 Boot 3 兼容版本;
- 修改 Jakarta 包名、配置属性和框架 API;
- 执行单元、集成、数据库、Security 和端到端测试;
- 检查 Actuator、日志、指标、Agent、容器镜像和外部 Servlet 容器;
- 灰度发布并观察启动、内存、延迟和错误指标。
分阶段、小提交迁移更容易定位问题,也便于在生产验证失败时回退。
八、用兼容矩阵安排迁移批次
一个中型服务假设有 40 个直接依赖,其中 8 个 Starter、3 个 Java Agent、1 个外部 Tomcat 和 6 处自定义 Security 配置。只让源码通过编译覆盖不了 Agent 字节码兼容、容器 Servlet 规范、数据库方言和安全默认值变化,因此迁移清单必须同时覆盖构建期与运行期。先把 40 个依赖按“Boot 管理、第三方 Starter、自研库、运行时工具”分类,再逐一确认目标版本,比遇到 NoSuchMethodError 后临时覆盖版本可靠。
| 迁移面 | Boot 2 常见基线 | Boot 3 关键变化 | 验证方式 |
|---|---|---|---|
| Java | Java 8/11 常见 | 最低 Java 17 | CI、镜像、生产 JVM 同步核对 |
| Spring | Framework 5 | Framework 6 | 编译并跑容器集成测试 |
| EE API | javax.servlet/persistence | jakarta.servlet/persistence | 源码、生成代码、外部容器 |
| ORM | Hibernate 5 常见 | Hibernate 6 系列 | 真实数据库查询与方言测试 |
| Security | 旧适配器式配置常见 | 组件式 SecurityFilterChain | 认证授权回归测试 |
| 观测 | 旧 Sleuth 等组合 | Observation/兼容 tracing 方案 | 指标与 trace 端到端验证 |
| 原生 | 实验或外置工具链 | AOT/Native 正式体系 | 单独构建与运行测试 |
latest Boot 2.7
→ 清除弃用项
→ Java 17 工具链
→ 兼容依赖与 Jakarta 源码
→ Boot 3 启动
→ 数据库 / Security / HTTP / Observability 回归
→ 灰度
迁移批次要可回退。若同时把业务模型、数据库结构和框架大版本一起改,线上异常很难判断来自哪一层;拆成小提交和独立验证阶段能显著降低定位成本。
迁移钩子:Boot 3 是“JDK + Spring + Jakarta + 生态依赖”四层平台迁移,编译成功只验证了最表面的一层。
九、常见误区与追问
- 误区:把 pom 中的 Boot 版本改成 3.x 就完成升级。 Java、Jakarta API、第三方库、容器、Agent 和配置都可能需要同步迁移。
- 误区:可以把源码里的所有 javax 全局替换成 jakarta。
javax.sql、javax.crypto等 Java SE API 没有迁移,机械替换会制造错误。 - 误区:升级到 Boot 3 就自动获得可运行的 Native Image。 AOT 能力进入正式体系,但反射、资源、代理和序列化仍需兼容性验证与提示。
- 追问:为什么建议先升级到最新 2.7.x? 2.7 是通往 3.0 的过渡基线,可先处理弃用项和 imports 等机制变化,缩小一次迁移跨度。
- 追问:外部 Tomcat 为什么也必须升级? Boot 3 应用使用 Jakarta Servlet API,旧的 javax Servlet 容器无法提供兼容运行环境。
- 追问:spring-boot-properties-migrator 应长期保留吗? 它适合迁移期发现重命名或删除的属性,修正完成后应移除,避免把诊断工具当兼容层。
十、加强记忆
Boot 2 到 3 是 Java 17 + Spring 6 + Jakarta EE 10 的平台迁移,核心风险在命名空间、依赖大版本、配置与运行环境。先站稳最新 2.7.x,再升级工具链和依赖,精准替换 Jakarta API,最后用真实集成测试验证,而不是只追求编译通过。