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

虚拟世界的AI魔法:AIGC引领元宇宙创作革命

虚拟世界的AI魔法:AIGC引领元宇宙创作革命

云边有个稻草人-ZEEKLOG博客——个人主页 热门文章_云边有个稻草人的博客-ZEEKLOG博客——本篇文章所属专栏 ~ 欢迎订阅~ 目录 1. 引言 2. 元宇宙与虚拟世界概述 2.1 什么是元宇宙? 2.2 虚拟世界的构建 3. AIGC在元宇宙中的应用 3.1 AIGC生成虚拟世界环境 3.2 AIGC生成虚拟角色与NPC 3.3 AIGC创造虚拟物品与资产 4. AIGC在虚拟世界与元宇宙的技术实现 4.1 生成式对抗网络(GANs)在元宇宙中的应用 4.2 自然语言处理(NLP)与虚拟角色的对话生成 4.3 计算机视觉与物理引擎 5. 持续创新:AIGC与元宇宙的未来趋势 5.1 个人化与定制化体验 5.

By Ne0inhk
AI的提示词专栏:LLaMA-2 与 Mixtral 的提示词调优技巧

AI的提示词专栏:LLaMA-2 与 Mixtral 的提示词调优技巧

AI的提示词专栏:LLaMA-2 与 Mixtral 的提示词调优技巧 本文围绕 LLaMA-2 与 Mixtral 两大模型的提示词调优展开,先分析二者核心特性,再针对性给出适配原则与实战技巧。LLaMA-2 因参数规模差异大、通用领域训练数据为主、指令敏感度低,需按参数分层设计提示词、补充领域知识、强化指令约束,还提供了结构化指令、Few-Shot 示例等 5 个实战技巧;Mixtral 凭借混合专家架构、长上下文窗口、强多语言能力,需引导激活对应专家模块、合理处理长文本、规范多语言输出,配套专家引导指令等 4 个技巧。文章还对比二者调优重点与适用场景,指出常见误区并给出避坑方案,最后总结核心思路并提供后续实践建议,助力开发者优化提示词、发挥模型性能。 人工智能专栏介绍     人工智能学习合集专栏是 AI 学习者的实用工具。它像一个全面的 AI 知识库,把提示词设计、AI 创作、智能绘图等多个细分领域的知识整合起来。

By Ne0inhk
一句话生成PCB?和AI聊聊天,就把板子画了!

一句话生成PCB?和AI聊聊天,就把板子画了!

在键盘上敲下一句“我要一个STM32的电机驱动板,带CAN总线”,几秒后,一张完整的原理图和PCB布局在你眼前展开——这不是科幻电影,而是AI给硬件工程师带来的真实震撼。 清晨的阳光洒进办公室,资深硬件工程师李工没有像往常一样直接打开Altium Designer。他对着电脑屏幕上的对话框,敲入了一行简单的需求描述:“设计一个基于ESP32的智能插座PCB,要求支持Wi-Fi控制、过载保护,尺寸尽量小巧。” 15分钟后,一份完整的原理图草案、经过初步优化的双层板布局,甚至是一份物料清单(BOM)初稿已经呈现在他面前。这不可思议的效率背后,正是AI驱动的PCB设计工具在重新定义电子设计的边界。 01 效率革命,从对话到电路板 如今的PCB设计领域正经历着一场静悄悄的革命。传统上,一块电路板从概念到图纸,需要工程师经历需求分析、器件选型、原理图绘制、布局布线等一系列复杂工序,耗时数天甚至数周。 AI工具的出现彻底改变了这一流程。这类工具的核心是经过海量电路数据和设计规则训练的大型语言模型,它们能理解自然语言描述的需求,自动完成从逻辑设计到物理实现的全流程或关键环节。 比如,当

By Ne0inhk
【AI开发】—— OpenCode双插件协同开发指南

【AI开发】—— OpenCode双插件协同开发指南

OpenCode双插件协同开发指南|Oh My OpenCode+Superpowers 兼顾效率与规范 很多同学在OpenCode中装完Superpowers后,都会有一个疑问:已经有了做代码规范的Superpowers,还有必要用Oh My OpenCode(OMOC)吗? 甚至装了两个插件后,不知道如何配合使用,导致要么只用到了其中一个的功能,要么让两者互相“冲突”,浪费了插件的核心价值。 其实答案很明确:两者是互补而非替代的关系,组合使用才是OpenCode的最优解。OMOC是「项目开发总指挥」,负责拆解任务、并行调度、自动化工具调用,主打一个提效率;Superpowers是「代码工程质检员」,负责约束AI遵循TDD、代码审查、重构等最佳实践,主打一个保规范。 这篇文章就把两者的核心区别讲透,再通过实操性拉满的协同开发教程,教你用OMOC+Superpowers开发项目,既让AI写代码又快又好,还能彻底摆脱“手动拆任务、反复改代码”的痛点,全程贴合开发实际,新手也能直接跟着做。 一、先搞懂:OMOC与Superpowers 核心区别(

By Ne0inhk