Spring Boot 4 升级实战:从3.x到4.0的分步升级保姆级指南

Spring Boot 4 升级实战:从3.x到4.0的分步升级保姆级指南

Spring Boot 4.0于2025年11月20日正式发布,是继2.x到3.x之后框架的又一次重大重构。本次升级将单体自动配置拆分为47个轻量模块、原生集成JSpecify空安全校验、内置API版本控制能力,同时基于Spring Framework 7.0打造,带来了更优的性能和开发体验。Spring Boot 3.5.x的支持将持续至2026年11月,为开发者预留了充足的迁移时间,而新特性带来的性能提升和开发效率优化,让迁移具备极高的实际价值。

本文基于生产环境服务的迁移实践,从版本前置升级、环境检查、核心配置修改、空安全修复、API版本控制配置等方面,提供可落地的分步迁移指南,同时梳理迁移过程中的常见问题与解决方案,帮你平稳完成从Spring Boot 3.5到4.0的升级。

一、Spring Boot 4.0 核心变更与升级价值

Spring Boot 4.0的核心更新围绕模块化、空安全、原生功能增强展开,最低要求Java 17(推荐Java 21 LTS),Kotlin项目需升级至2.2及以上版本,核心变更及升级带来的实际价值如下:

1.1 核心变更

  1. 自动配置模块化:将原6.2MB的spring-boot-autoconfigure单体JAR拆分为47个专属轻量模块,引入spring-boot-starter-web仅加载WebMVC配置,不再包含批处理、MongoDB等无关配置;
  2. 空安全体系升级:使用JSpecify 1.0替代原org.springframework.lang的空注解,支持编译期空安全校验,提前规避NPE问题;
  3. 原生API版本控制:无需自定义RequestMappingHandlerMapping或路径拼接,通过注解和配置即可实现Header/路径式API版本控制;
  4. 声明式HTTP客户端:内置声明式HTTP客户端,无需依赖Feign等第三方库;
  5. 可观测性增强:集成Micrometer 2.0,支持SSL健康检查,监控能力更完善;
  6. 依赖与测试调整:移除MockitoTestExecutionListener,需改用MockitoExtension;精简spring-boot-starter-parent结构;核心消息抽象迁移至spring-messaging模块。

1.2 实际升级价值

基于生产服务的迁移实测,Spring Boot 4.0相比3.5.x带来了显著的性能和开发体验提升:

  • 镜像体积减少19%:从387MB降至312MB,降低容器部署的存储和网络成本;
  • 启动时间缩短33%:从4.2秒降至2.8秒,提升服务弹性扩缩容效率;
  • 消除冗余代码:原生API版本控制可移除200行左右的自定义路由代码;
  • 提前规避BUG:编译期空安全校验可发现潜在的空指针问题,减少生产环境故障;
  • 依赖更简洁:模块化的自动配置让依赖图谱更清晰,减少无用依赖的加载。

二、迁移前置准备

2.1 版本前置升级:先升级至3.5.x最新版

禁止直接从3.3及以下版本跳级至4.0,需先升级到Spring Boot 3.5.x的最新版本(截至2025年12月为3.5.6),该步骤可提前暴露弃用警告,确保依赖的兼容性。

Maven配置修改
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.5.6</version></parent>
Gradle配置修改
plugins { id 'org.springframework.boot' version '3.5.6'}

升级后执行测试,修复所有失败用例:

# Maven ./mvnw clean test# Gradle ./gradlew clean test

关键修复:3.4开始弃用MockitoTestExecutionListener,4.0直接移除,若测试类使用@Mock/@Captor但未引入MockitoExtension,会出现Mock对象为null的问题,需在测试类添加:

importorg.junit.jupiter.api.extension.ExtendWith;importorg.mockito.junit.jupiter.MockitoExtension;@ExtendWith(MockitoExtension.class)classMyServiceTest{@MockprivateMyRepository repo;// 测试逻辑}

2.2 检查并升级Java/Kotlin版本

Spring Boot 4.0要求Java 17及以上(推荐Java 21 LTS),Kotlin项目需Kotlin 2.2及以上,先检查当前版本:

java -version 
Java 21 安装(主流系统)

Ubuntu:

sudoapt update sudoaptinstall openjdk-21-jdk 

macOS(Homebrew):

brew install openjdk@21 
构建文件中指定Java版本

Gradle(build.gradle):

java { sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 }

Maven(pom.xml):

<properties><java.version>21</java.version></properties>
Kotlin版本升级(pom.xml)
<kotlin.version>2.2.0</kotlin.version>

修改后重新构建并测试,确保基础环境无问题。

三、正式升级至Spring Boot 4.0.0

完成前置准备后,将Spring Boot版本正式修改为4.0.0,这一步是迁移的核心,会出现依赖和编译相关的错误,需逐一修复。

3.1 修改构建文件版本

Maven
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>4.0.0</version></parent>
Gradle
plugins { id 'org.springframework.boot' version '4.0.0'}

3.2 执行构建并修复依赖缺失问题

# Maven ./mvnw clean package # Gradle ./gradlew clean build 

最常见错误:模块化拆分后,直接导入自动配置类但未引入对应starter的,会出现类缺失,需添加专属starter依赖。
示例:使用Spring Data MongoDB需添加:

<!-- 非响应式 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency><!-- 响应式 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb-reactive</artifactId></dependency>

若未使用starter,需手动添加对应的自动配置模块(模块列表参考Spring Boot 4.0官方迁移指南),例如使用TestRestTemplate需添加:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure-web</artifactId></dependency>

四、修复JSpecify空安全警告

Spring Boot 4.0全面采用JSpecify 1.0的空注解(org.jspecify.annotations),替代原Spring的空注解(org.springframework.lang),支持编译期空安全校验,是本次升级的核心重点之一。

4.1 添加JSpecify依赖

<dependency><groupId>org.jspecify</groupId><artifactId>jspecify</artifactId><version>1.0.0</version></dependency>

4.2 开启包级别的空安全标记

创建package-info.java文件,标记当前包为默认非空,仅显式标注@Nullable的对象可为空,实现全局空安全约束:

@NullMarkedpackagecom.example.myapp;importorg.jspecify.annotations.NullMarked;

4.3 修复具体的空安全警告

添加依赖和标记后,IDEA 2025.3+/Eclipse(Spring Tools)会在编译期提示空安全警告,核心修复场景为未处理可空对象的空值情况

典型场景:仓库查询结果未判空

原代码(有警告)

@GetMapping("/users/{id}")publicUsergetUser(@PathVariableLong id){// findById返回@Nullable User/Optional<User>,直接返回会触发警告return userRepository.findById(id);}

修复后代码

importorg.springframework.http.HttpStatus;importorg.springframework.web.server.ResponseStatusException;@GetMapping("/users/{id}")publicUsergetUser(@PathVariableLong id){// 方式1:Optional判空return userRepository.findById(id).orElseThrow(()->newResponseStatusException(HttpStatus.NOT_FOUND));// 方式2:直接判空/* User user = userRepository.findById(id); if (user == null) { throw new ResponseStatusException(HttpStatus.NOT_FOUND); } return user; */}

4.4 (可选)构建期强制空安全校验

若需要在CI/构建阶段强制校验空安全,可集成NullAway,拒绝空安全违规的代码构建(需Java 21+),Maven配置示例:

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><compilerArgs><arg>-XDaddTypeAnnotationsToSymbol=true</arg><arg>-Xplugin:NullAway</arg></compilerArgs><annotationProcessorPaths><path><groupId>com.uber.nullaway</groupId><artifactId>nullaway</artifactId><version>0.10.12</version></path></annotationProcessorPaths></configuration></plugin>

执行mvn compile,若存在空安全违规,构建会直接失败。

五、配置原生API版本控制

Spring Boot 4.0内置API版本控制能力,无需自定义代码,支持Header式路径式两种方式,彻底替代传统的路径拼接/自定义处理器方案。

5.1 核心配置:选择版本控制方式

application.properties/application.yml中配置版本控制的核心规则,二选一即可。

方式1:Header式版本控制(推荐)

通过请求头传递API版本,保持URL整洁,适合内部服务/前后端分离项目:

# 自定义头名称为API-Version spring.mvc.apiversion.use.header=API-Version 
方式2:路径式版本控制

通过URL路径段传递API版本,适合浏览器端/无请求头控制的场景:

# 数字1表示版本为URL的第2个路径段(索引从0开始) spring.mvc.apiversion.use.path-segment=1 # 示例:/api/v1.2/users → 版本为v1.2 

5.2 接口中添加版本注解

@GetMapping/@PostMapping等注解中通过version属性指定接口版本,支持多版本接口共存。

Header式版本控制示例
importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.web.bind.annotation.RequestMapping;@RestController@RequestMapping("/api/users")publicclassUserController{// 1.0版本接口:返回旧版VO@GetMapping(value ="/{id}", version ="1.0")publicUserV1getUserV1(@PathVariableLong id){return userService.getV1User(id);}// 1.1版本接口:返回新版VO(含扩展字段)@GetMapping(value ="/{id}", version ="1.1")publicUserV2getUserV2(@PathVariableLong id){return userService.getV2User(id);}}
客户端调用示例(curl)
# 调用1.0版本curl -H "API-Version: 1.0" http://localhost:8080/api/users/1 # 调用1.1版本curl -H "API-Version: 1.1" http://localhost:8080/api/users/1 

5.3 高级用法:基线版本匹配

使用1.0+表示匹配1.0及以上所有版本,避免未变更接口的版本注解重复编写:

// 匹配1.0、1.1、1.2等版本,除非有更具体的版本接口@GetMapping(value ="/list", version ="1.0+")publicList<UserV1>getUserList(){return userService.listV1Users();}

5.4 服务间调用:API版本自动注入

使用RestClient调用其他服务时,可配置版本注入器,自动添加版本头,无需手动设置:

importorg.springframework.web.client.RestClient;importorg.springframework.web.servlet.mvc.method.annotation.ApiVersionInserter;RestClient client =RestClient.builder().baseUrl("http://localhost:8080")// 配置Header式版本注入.apiVersionInserter(ApiVersionInserter.useHeader("API-Version")).build();// 调用时指定版本,自动添加API-Version:1.1头UserV2 user = client.get().uri("/api/users/1").apiVersion("1.1").retrieve().body(UserV2.class);

六、替换所有弃用的API

Spring Boot 4.0移除了大量弃用的类和注解,需在IDE中检查删除线标注的弃用代码,替换为官方推荐的替代方案,核心替换点如下:

6.1 空注解替换

// 旧:Spring原生注解importorg.springframework.lang.Nullable;// 新:JSpecify注解importorg.jspecify.annotations.Nullable;

6.2 Mock相关注解替换

// 旧importorg.springframework.boot.test.mock.mockito.MockBean;// 新(3.5+推荐)importorg.springframework.test.context.bean.override.mockito.MockitoBean;// 或直接使用@Mock + MockitoExtension(推荐)

6.3 核心类包迁移

核心消息抽象从spring-context迁移至spring-messaging,若使用相关类,需调整导入包(IDE会自动提示)。

七、迁移过程中的常见问题与解决方案

结合生产服务的迁移实践,梳理6类最常见的问题及快速解决方案,覆盖依赖、测试、配置等核心场景。

问题1:TestRestTemplate 无法解析

错误Cannot resolve symbol 'TestRestTemplate'
解决方案:添加spring-boot-starter-test依赖(测试环境)或手动添加web自动配置模块:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>

问题2:MongoTemplate/RedisTemplate 注入失败

错误No qualifying bean of type 'org.springframework.data.mongodb.core.MongoTemplate'
解决方案:模块化后,需添加对应的数据库starter,而非仅依赖核心包:

<!-- MongoDB --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency><!-- Redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

问题3:@Mock 字段为null,测试报NPE

错误NullPointerException(Mock对象未初始化)
解决方案:测试类添加@ExtendWith(MockitoExtension.class),移除弃用的@RunWith(MockitoJUnitRunner.class)

问题4:JSpecify 注解无提示,IDEA不识别

解决方案

  1. 升级IDEA至2025.3及以上版本;
  2. 项目SDK设置为Java 21;
  3. 确保添加了JSpecify 1.0.0依赖;
  4. IDEA中开启File > Settings > Build, Execution, Deployment > Compiler > Java Compiler的注解处理。

问题5:路径式版本控制返回404

错误:配置路径式版本控制后,所有请求返回404
解决方案@RequestMapping中必须包含{version}路径变量,Spring通过该变量提取版本:

// 正确@RequestMapping("/api/{version}/users")// 错误@RequestMapping("/api/users")

问题6:Maven依赖冲突,Spring Framework版本低于7.0

错误Dependency convergence error(依赖树中存在Spring Framework <7.0的版本)
解决方案:查看依赖树,找到引入低版本Spring的依赖并升级/排除:

# 查看Maven依赖树 ./mvnw dependency:tree # 排除低版本依赖示例<dependency><groupId>com.example</groupId><artifactId>old-dependency</artifactId><exclusions><exclusion><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></exclusion></exclusions></dependency>

八、Spring Boot 3.5 vs 4.0 核心指标对比

基于实际生产服务的迁移实测,核心指标对比如下,直观体现升级的价值:

指标Spring Boot 3.5.6Spring Boot 4.0.0变化
容器镜像体积387 MB312 MB减少19%
服务启动时间4.2s2.8s缩短33%
空安全校验编译期警告/强制提前规避NPE
API版本控制需自定义代码框架原生支持移除200行代码
自动配置结构1个单体JAR47个轻量模块依赖更简洁
Java基线17(可选21)17(推荐21)一致
Kotlin基线1.92.2强制升级
测试框架支持旧版Mockito仅支持MockitoExtension规范测试写法

九、后续规划与生态展望

9.1 版本支持与后续升级

  • Spring Boot 3.5.x:官方支持至2026年11月,可根据业务节奏择机迁移;
  • Spring Boot 4.0.1:2025年12月9日发布,仅修复小BUG,无破坏性变更,可直接升级;
  • Spring Boot 4.1:预计2026年Q2发布,重点增强响应式能力、进一步模块化,同时优化GraalVM原生镜像构建,降低无服务应用的冷启动时间。

9.2 生态兼容注意事项

目前部分第三方库尚未完成Spring Framework 7.0的适配,迁移前需检查核心依赖的兼容性:

  1. 优先使用Spring官方生态的依赖,兼容性最高;
  2. 自定义starter/内部库需提前完成4.0适配;
  3. 日志、监控等通用库,优先升级至最新版本。

9.3 迁移后的最佳实践

  1. 全面推行空安全编码:基于JSpecify规范,所有新代码添加空注解,逐步改造旧代码;
  2. 基于原生API版本控制:统一团队的API版本规范,避免自定义方案的碎片化;
  3. 精简依赖:移除无用的starter,利用模块化优势进一步降低镜像体积;
  4. 开启构建期空安全强制校验:在CI/CD流水线中集成NullAway,拒绝空安全违规代码合并。

十、总结

Spring Boot 4.0是一次高性能、高安全性、高开发效率的重大升级,模块化的自动配置、原生的空安全校验、内置的API版本控制三大核心特性,不仅带来了显著的性能提升,更从框架层面规范了开发流程,提前规避生产环境的常见BUG。

本次迁移的核心原则是分步升级、前置修复:先升级至3.5.x最新版,修复弃用警告,再检查并升级基础环境,最后正式升级至4.0并修复依赖、编译问题。从实际实践来看,无复杂自定义配置的服务,90分钟内可完成迁移;存在自定义自动配置/多依赖的服务,约4小时可完成,整体迁移成本可控。

对于拥有公共API的服务,原生API版本控制特性足以成为迁移的核心理由;对于追求性能的容器/无服务部署场景,19%的镜像体积减少+33%的启动时间缩短能直接降低运行成本;而空安全校验则是长期的价值,能持续减少生产环境的空指针故障。

Read more

这回真的“装”到了!来OpenClaw全国纵深行,你只需要带一台电脑……

这回真的“装”到了!来OpenClaw全国纵深行,你只需要带一台电脑……

AI Agent 的风,已经从 GitHub 吹到了线下。 过去几个月,越来越多开发者开始讨论一个问题: 当 AI 不再只是聊天,而是可以执行任务,软件会变成什么样? 在这股浪潮中,一个开源项目迅速进入开发者视野——OpenClaw,在 GitHub 上获得大量关注,相关教程、实践案例不断出现。有人用它自动整理资料,有人用它管理开发流程,还有人尝试让它执行复杂的工作流。 很多开发者第一次意识到: AI 不只是工具,它可能成为“执行者”。 不过,在技术社区之外,大多数人对 Agent 的理解仍停留在概念层面。 * AI Agent 到底是什么? * 如何在自己的电脑上运行? * 普通开发者能否真正用起来? 带着这些问题,一场围绕 OpenClaw 的开发者城市行动正在展开。 ZEEKLOG 发起的OpenClaw 全国纵深行将走进 20 个城市,用最直接的方式回答一个问题——如果

By Ne0inhk
字节辟谣「武汉全员被裁」:超2000人base武汉;315曝光给AI大模型“投毒”已成产业链;腾讯正式成为OpenClaw赞助商 | 极客头条

字节辟谣「武汉全员被裁」:超2000人base武汉;315曝光给AI大模型“投毒”已成产业链;腾讯正式成为OpenClaw赞助商 | 极客头条

「极客头条」—— 技术人员的新闻圈! ZEEKLOG 的读者朋友们好,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧。(投稿或寻求报道:[email protected]) 整理 | 苏宓 出品 | ZEEKLOG(ID:ZEEKLOGnews) 一分钟速览新闻点! * 腾讯正式成为 OpenClaw 赞助商 * 字节辟谣「武汉全员被裁」:超 2000 人 base 武汉,将加大对湖北投入 * 2026 北京亦庄人形机器人半马完成首场练习测试 * 美团 CEO 王兴:我们都应该努力“减少登味”,内部不要再叫我“兴哥” * 向 AI 投毒已成产业链!315 晚会曝光 GEO 技术:虚构产品都能成 AI 标准答案 * 雷军官宣:新一代小米

By Ne0inhk
只因一个高级词,作文被判“18% AI生成”!AI检测「荒诞现状」:写得太好=AI作弊,学生被逼“降智”写作

只因一个高级词,作文被判“18% AI生成”!AI检测「荒诞现状」:写得太好=AI作弊,学生被逼“降智”写作

【ZEEKLOG 编者按】当生成式 AI 迅速进入校园,许多学校的第一反应是部署各种“AI 检测工具”,试图用技术手段识别学生是否在作业中使用了 AI。然而,这种看似合理的做法,正在产生一些出乎意料的副作用:学生因为用词稍微“高级”一点就被判定为“AI生成”,优秀写作反而变成一种风险;为了避免被误判,一些原本不使用 AI 的学生开始主动学习和使用 AI 工具,只为“自证清白”。 原文链接:https://www.techdirt.com/2026/03/06/were-training-students-to-write-worse-to-prove-theyre-not-robots-and-its-pushing-them-to-use-more-ai/ 作者 | Mike Masnick      编译 | 郑丽媛 出品 | ZEEKLOG(ID:ZEEKLOGnews)  大约一年半前,我写过一件发生在我孩子身上的事。 当时学校给每个学生发了一台 Chromebook,上面预装了一款 AI

By Ne0inhk
因AI“认错脸”,50岁的她坐了6个月牢:被当诈骗犯抓走,回来后房子、车子和狗全没了!

因AI“认错脸”,50岁的她坐了6个月牢:被当诈骗犯抓走,回来后房子、车子和狗全没了!

整理 | 郑丽媛 出品 | ZEEKLOG(ID:ZEEKLOGnews) 如果有一天,你只是长得像某个人,就被 AI 认定为罪犯——然后被警方带走、关进监狱半年,你会怎么办? 最近,外媒曝光了一起离谱案件:一位来自美国田纳西州的 50 岁女性,仅仅因为 AI 人脸识别误判,被警方当作银行诈骗案的主犯逮捕,并在监狱里待了将近  6 个月。直到银行流水证明她当时根本不在案发地,检方才撤销全部指控。 然而,当她终于重获自由时,她的生活已经几乎被毁掉——房没了,车没了,甚至连她养的宠物狗也没了。 (Angela Lipps 事后接受媒体采访时的照片) 从没坐过飞机,却被押送 1200 英里受审 如开头所说,这位当事人名叫 Angela Lipps,今年 50 岁,住在美国田纳西州中北部。 她有三个已经成年的孩子,

By Ne0inhk