一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

万字避坑:Spring Boot 3.x 升 4.0 最全升级指南 - 附 Migration Checklist 建议收藏

时间:2026-07-17 08:44:56 编辑:袖梨 来源:一聚教程网


前言:升级不可怕,可怕的是不知道要改什么

兄弟们,升级 Spring Boot 大版本,最让人焦虑的是什么?

不是"写新代码",而是**"改旧代码"**——你到底要改哪些地方?改了会不会引发连锁故障?线上跑着的服务会不会突然挂掉?

好消息是,Spring Boot 4 的升级路径比 Boot 2→3 平滑得多。没有再来一次包名级别的全量地震(那个已经在 Boot 3 做完了),但仍有一批"必须改"和"建议改"的要点。

本文逐一拆解 10 大类升级变更项,每项都基于 Spring Boot 4.1.0 源码验证,并标注影响等级。先看这张等级表,心里有数:

影响等级含义你需要做什么
必须改不改编译/启动失败立刻改,没商量
建议改旧方式仍可用但已被弃用,未来版本将移除有空就改,别拖
零成本收益新增能力,不需要改代码就能享受白嫖,爽

️ 先认识一个"救命"模块:spring-boot-properties-migrator

在逐项讲解前,先给大家介绍一个升级路上的"救命稻草"——spring-boot-properties-migrator。这个模块能帮你自动检测和迁移已弃用的配置项,省去大量人工排查的功夫。

源码切入点

源码位置core/spring-boot-properties-migrator/

这个模块的核心类是 PropertiesMigrationListener,它实现了 ApplicationListener<SpringApplicationEvent>,在应用启动的两个关键时刻介入:

 复制代码// PropertiesMigrationListener.java 关键逻辑
@Override
public void onApplicationEvent(SpringApplicationEvent event) {
    if (event instanceof ApplicationPreparedEvent preparedEvent) {
        onApplicationPreparedEvent(preparedEvent);  // ① 环境准备后扫描配置
    }
    if (event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) {
        logLegacyPropertiesReport();                 // ② 启动完成/失败时输出报告
    }
}

它的工作流程如下:

怎么用?一行依赖搞定

 复制代码<!-- Maven -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-properties-migrator</artifactId>
    <scope>runtime</scope>
</dependency>
 复制代码// Gradle
runtimeOnly("org.springframework.boot:spring-boot-properties-migrator")

启动应用后,如果配置文件中有已弃用的属性,控制台会直接告诉你该改成什么:

 复制代码WARN  [PropertiesMigrationListener] -
The use of configuration keys that have been renamed was found in the environment:Property source 'applicationConfig: [classpath:/application.yml]':
    Key: server.servlet.path
        Line: 3
        Replacement: spring.mvc.servlet.path

10 大类升级变更逐项指南(硬核预警)

接下来进入正文,每一项都附带源码证据 + 改写示例,大家可以对照自己的项目逐项排查。


变更 1:JDK 版本基线 — JDK 17 硬性要求,JDK 25 强烈推荐

源码证据starter/spring-boot-starter-parent/build.gradle

 复制代码delegate."java.version"('17')

Spring Boot 4 的 JDK 17 是硬性编译基线,不可降级。同时,官方强烈推荐使用 JDK 25,以充分利用:

JDK 特性最低版本在 Spring Boot 4 中的应用
虚拟线程 GAJDK 21spring.threads.virtual.enabled=true 的前置条件
Record 类JDK 16 (GA 17)配置属性绑定、DTO 简化
Sealed ClassJDK 17模块化自动配置的类型层级
Pattern Matching for switchJDK 21框架内部条件判断简化
Scoped ValuesJDK 21 (GA 25)替代 ThreadLocal 的上下文传递(4.1 增强)
Stream GatherersJDK 24框架内部流处理优化

源码证据Threading.java 中的 JDK 版本判断

 复制代码VIRTUAL {
    @Override
    public boolean isActive(Environment environment) {
        return environment.getProperty("spring.threads.virtual.enabled",
                boolean.class, false)
            && JavaVersion.getJavaVersion()
                .isEqualOrNewerThan(JavaVersion.TWENTY_ONE);  // 虚拟线程需要 JDK 21+
    }
};

升级操作

 复制代码# 检查当前 JDK 版本
java -version# 推荐:安装 JDK 25(以 SDKMAN 为例)
sdk install java 25.0.1-tem
sdk use java 25.0.1-tem

变更 2:jakarta.* 包名 — 继续深化,Servlet 6.1 全面就绪

Spring Boot 4 底层使用 Tomcat 11.0.22(源码 gradle.properties 第 27 行):

 复制代码tomcatVersion=11.0.22

Tomcat 11 实现了 Jakarta Servlet 6.1 规范,对 javax.servlet.* 零容忍——任何残留都会导致 ClassNotFoundException

需要确认的包名迁移清单

旧包名 (javax)新包名 (jakarta)涉及场景
javax.servlet.*jakarta.servlet.*Filter、Servlet、Listener
javax.persistence.*jakarta.persistence.*JPA Entity、Repository
javax.validation.*jakarta.validation.*@Valid、@NotNull 等校验注解
javax.transaction.*jakarta.transaction.*JTA 事务管理(UserTransactionTransactionManager
javax.annotation.*jakarta.annotation.*@PostConstruct、@PreDestroy、@Resource
javax.mail.*jakarta.mail.*邮件发送
javax.json.*jakarta.json.*JSON 处理

一行命令快速排查(在项目根目录执行):

 复制代码# 检查是否还有 javax 包引用
grep -r "import javax." --include="*.java" src/ | grep -v "javax.annotation.processing"# 检查 Maven/Gradle 依赖中是否还有 javax 坐标
mvn dependency:tree | grep "javax."      # Maven
gradle dependencies | grep "javax."       # Gradle

如果仍有 javax 依赖的第三方库,可以使用 jakarta-transformer 工具进行字节码级别的自动转换:

 复制代码<!-- Maven plugin: 自动转换 javax → jakarta -->
<plugin>
    <groupId>org.eclipse.transformer</groupId>
    <artifactId>transformer-maven-plugin</artifactId>
    <version>1.0.0</version>
    <executions>
        <execution>
            <goals><goal>transform</goal></goals>
        </execution>
    </executions>
</plugin>

变更 3:Jackson 2.x → 3.x — 核心类库包名全变,但注解原地不动

这是 Boot 4 升级中影响面最大的代码变更。Spring Boot 4 默认使用 Jackson 3(tools.jackson.* 包名),Jackson 2 仅作为过渡支持。

源码证据gradle.properties

 复制代码jackson2Version=2.21.4    # 遗留支持(已弃用)
jacksonVersion=3.1.4      # 主力版本

核心变化:类库包名变了,但注解包名不变

 复制代码//  Jackson 2 核心类(Spring Boot 3.x 时代)
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;//  Jackson 3 核心类(Spring Boot 4.x 默认)
import tools.jackson.core.JsonFactory;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.json.JsonMapper;//  注解包名保持不变!(向下兼容)
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;

整个 spring-boot-jackson2 模块已弃用

源码证据module/spring-boot-jackson2/ 中所有核心类

 复制代码// JsonComponent.java 第 61-68 行
@Deprecated(since = "4.0.0", forRemoval = true)
public @interface JsonComponent { ... }// JsonObjectSerializer.java 第 35-38 行
@Deprecated(since = "4.0.0", forRemoval = true)
public abstract class JsonObjectSerializer<T> { ... }// Jackson2BackgroundPreinitializer.java 第 27-29 行
@Deprecated(since = "4.0.0", forRemoval = true)
public class Jackson2BackgroundPreinitializer { ... }

弃用时间线:Jackson 2 支持将在 Spring Boot 4.3.0 中彻底移除。也就是说,你有 4.0 → 4.3 的过渡窗口期,但别拖到最后。

必须修改的代码

 复制代码//  Boot 3.x:使用 Jackson2ObjectMapperBuilder
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
    return builder -> builder.serializationInclusion(JsonInclude.Include.NON_NULL);
}//  Boot 4.x:使用 JsonMapper.builder() + JsonMapperBuilderCustomizer
@Bean
public JsonMapperBuilderCustomizer customizer() {
    return builder -> builder.serializationInclusion(JsonInclude.Include.NON_NULL);
}

Spring Boot 4.1 新增的 Jackson 配置(spring.jackson.factory.*

这个新配置可以帮你防御 JSON 炸弹攻击,之前需要手动写代码拦截的,现在配置文件搞定:

 复制代码spring:
  jackson:
    factory:
      constraints:
        read:
          max-nesting-depth: 500         # JSON 最大嵌套深度
          max-document-length: -1        # 最大文档长度(-1 不限)
          max-string-length: 100000000   # 最大字符串长度
          max-number-length: 1000        # 最大数字长度
          max-name-length: 50000         # 最大属性名长度
        write:
          max-nesting-depth: 500         # 序列化最大嵌套深度

批量替换脚本(懒人福音)

 复制代码# 查找所有使用 Jackson 2 核心包名的 Java 文件
grep -r "import com.fasterxml.jackson.(core|databind|dataformat)" --include="*.java" src/# 批量替换(macOS 使用 sed -i '')
find src/ -name "*.java" -exec sed -i '' 
  -e 's/import com.fasterxml.jackson.core./import tools.jackson.core./g' 
  -e 's/import com.fasterxml.jackson.databind./import tools.jackson.databind./g' 
  -e 's/import com.fasterxml.jackson.dataformat./import tools.jackson.dataformat./g' {} +# ️ 注意:不要替换注解包名!
# com.fasterxml.jackson.annotation.* 保持不变

变更 4:Undertow 被彻底移除 — 必须切换 Web 容器

在 Spring Boot 4.1.0 的源码中,没有任何 Undertow 相关文件

 复制代码$ find . -name "*undertow*" 2>/dev/null
# 无结果 —— Undertow 已被完全移除

starter/ 目录下,只有以下 Web 容器 Starter:

 复制代码spring-boot-starter-tomcat        ← 默认(Servlet 容器)
spring-boot-starter-jetty         ← 备选(Servlet 容器)
spring-boot-starter-reactor-netty ← WebFlux 默认(响应式容器)

如果你之前在 Boot 3.x 中使用 Undertow

Maven 切换示例

 复制代码<!--  Boot 3.x:使用 Undertow -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency><!--  Boot 4.x:切换为 Tomcat(默认,如果用了 spring-boot-starter-web 则无需额外添加) -->
<!-- Tomcat 已包含在 spring-boot-starter-web 的传递依赖中 --><!-- 或切换为 Jetty -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

Gradle 切换示例

 复制代码//  Boot 3.x
implementation("org.springframework.boot:spring-boot-starter-undertow")//  Boot 4.x — 排除默认 Tomcat,使用 Jetty
implementation("org.springframework.boot:spring-boot-starter-web") {
    exclude(module = "spring-boot-starter-tomcat")
}
implementation("org.springframework.boot:spring-boot-starter-jetty")

Undertow 特有配置需要迁移

Undertow 配置 (已失效)对应 Tomcat/Jetty 配置
server.undertow.*迁移到 server.tomcat.*server.jetty.*
server.undertow.accesslog.*server.tomcat.accesslog.*
Undertow 自定义 UndertowBuilderCustomizerTomcatServletWebServerFactoryCustomizerJettyServletWebServerFactoryCustomizer

变更 5:AntPathMatcher 弃用 — 统一使用 PathPatternParser

源码证据WebMvcProperties.java

 复制代码public enum MatchingStrategy {
    /**
     * @deprecated since 4.0.0 for removal in 4.2.0 in favor of
     * {@link #PATH_PATTERN_PARSER}
     */
    @Deprecated(since = "4.0.0", forRemoval = true)
    ANT_PATH_MATCHER,    PATH_PATTERN_PARSER
}

Spring Boot 4 统一使用 PathPatternParser 作为 URL 路径匹配策略,AntPathMatcher 已被弃用,将在 4.2.0 中移除

受影响的配置

 复制代码#  Boot 3.x:显式指定 AntPathMatcher
spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher#  Boot 4.x:必须切换(或删除,默认就是 PATH_PATTERN_PARSER)
spring:
  mvc:
    pathmatch:
      matching-strategy: path_pattern_parser

如果你的代码中有自定义 AntPathMatcher

 复制代码//  Boot 3.x
@Bean
public AntPathMatcher antPathMatcher() {
    return new AntPathMatcher();
}//  Boot 4.x:改用 PathPatternParser
@Bean
public PathPatternParser pathPatternParser() {
    PathPatternParser parser = new PathPatternParser();
    parser.setCaseSensitive(false);
    return parser;
}

变更 6:EnvironmentPostProcessor 包名迁移

源码证据core/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessor.java

 复制代码/**
 * @deprecated since 4.0.0 for removal in 4.2.0 in favor of
 * {@link org.springframework.boot.EnvironmentPostProcessor}
 */
@FunctionalInterface
@Deprecated(since = "4.0.0", forRemoval = true)
public interface EnvironmentPostProcessor {
    // 旧接口,位于 org.springframework.boot.env 包
}

Spring Boot 4 将 EnvironmentPostProcessororg.springframework.boot.env 包提升到 org.springframework.boot 包:

 复制代码//  Boot 3.x
import org.springframework.boot.env.EnvironmentPostProcessor;//  Boot 4.x
import org.springframework.boot.EnvironmentPostProcessor;

新的 EnvironmentPostProcessor 接口功能与旧接口基本一致,核心差异在于包名和构造器参数支持:

  • 包名从 org.springframework.boot.env 提升到 org.springframework.boot
  • 构造器可以接收 DeferredLogFactory(延迟日志工厂)和 ConfigurableBootstrapContext(可配置的启动上下文)
  • 排序方式:实现 Ordered 接口或标注 @Order 注解(与旧接口相同)

变更 7:RestTemplateBuilder.rootUri() 重命名为 baseUri()

源码证据RestTemplateBuilder.java

 复制代码/**
 * @deprecated since 4.1.0 for removal in 4.3.0 in favor of {@link #baseUri(String)}
 */
@Deprecated(forRemoval = true, since = "4.1.0")
public RestTemplateBuilder rootUri(@Nullable String rootUri) {
    // ...
}
 复制代码//  Boot 4.0.x(4.1.0 中弃用)
RestTemplate restTemplate = new RestTemplateBuilder()
    .rootUri("http://api.example.com")
    .build();//  Boot 4.1.0+
RestTemplate restTemplate = new RestTemplateBuilder()
    .baseUri("http://api.example.com")
    .build();

变更 8:SessionProperties.determineTimeout() 弃用

源码证据SessionProperties.java

 复制代码/**
 * @deprecated since 4.0.1 for removal in 4.2.0 in favor of {@link SessionTimeout}
 */
@Deprecated(since = "4.0.1", forRemoval = true)
public Duration determineTimeout(Supplier<Duration> fallbackTimeout) {
    return (this.timeout != null) ? this.timeout : fallbackTimeout.get();
}

如果代码中直接调用了 sessionProperties.determineTimeout(...),需要改为使用 SessionTimeout 机制。


变更 9:Health 模块三大类弃用

源码证据module/spring-boot-health/src/main/java/

 复制代码// 以下三个类均 @Deprecated(since = "4.1.0", forRemoval = true)
@Deprecated(since = "4.1.0", forRemoval = true)
public class SimpleStatusAggregator { ... }@Deprecated(since = "4.1.0", forRemoval = true)
public interface HttpCodeStatusMapper { ... }@Deprecated(since = "4.1.0", forRemoval = true)
public class SimpleHttpCodeStatusMapper { ... }

如果你自定义了健康检查的状态聚合逻辑,需要使用新的 API 替代(Spring Boot 4.1 推荐使用 StatusAggregator 实现)。


变更 10:spring.factories 中 AutoConfiguration 键的彻底移除

Spring Boot 3.x 开始,自动配置类的注册方式从 spring.factories 中的 org.springframework.boot.autoconfigure.EnableAutoConfiguration 键迁移到 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件。

Spring Boot 4 彻底完成了这个迁移。虽然 spring.factories 本身仍然用于其他 SPI(ApplicationContextInitializerApplicationListenerFailureAnalyzer 等),但自动配置类已不再从 spring.factories 读取。

源码证据AutoConfigurationImportSelector.java 只读取 AutoConfiguration.imports

 复制代码// 自动配置只从 .imports 文件加载
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
        @Nullable AnnotationAttributes attributes) {
    ImportCandidates importCandidates = ImportCandidates.load(
            this.autoConfigurationAnnotation, getBeanClassLoader());
    List<String> configurations = importCandidates.getCandidates();
    Assert.state(!CollectionUtils.isEmpty(configurations),
            "No auto configuration classes found in META-INF/spring/"
                    + this.autoConfigurationAnnotation.getName() + ".imports.");
    return configurations;
}

如果你的项目有自定义 AutoConfiguration,需要确认注册方式:

 复制代码#  Boot 2.x 方式:META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.example.MyAutoConfiguration#  Boot 3.x/4.x 方式:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.MyAutoConfiguration

影响面分级总结:一张图看懂你要改什么


升级决策树:跟着走,不迷路

不知道自己项目要改哪些?跟着这棵决策树走一遍:


升级步骤 Checklist(建议收藏,对照打勾)

阶段一:环境准备

  • JDK 升级到 17+(推荐 JDK 25)
     复制代码java -version  # 确认版本
    
  • 更新 Spring Boot 版本号
     复制代码<!-- Maven parent -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.1.0</version>
    </parent>
    
  • 更新 Gradle 插件
     复制代码plugins {
        id 'org.springframework.boot' version '4.1.0'
    }
    

阶段二:依赖检查

  • 移除 Undertow 依赖,切换为 Tomcat 或 Jetty
  • 检查 Jackson 依赖
    • 如果直接依赖了 jackson-databind 等核心库,将 com.fasterxml.jackson.core/databind/dataformat 替换为 tools.jackson.*
    • 如果使用了 spring-boot-starter-json(通过 spring-boot-starter-web 间接引入的情况最常见):无需改动,该 Starter 在 Boot 4 中已自动切换为依赖 spring-boot-jackson(Jackson 3)
    • 注解依赖 (com.fasterxml.jackson.annotation.*) 不需要改
  • 检查是否有 javax.* 依赖残留
     复制代码mvn dependency:tree | grep "javax."  # Maven
    gradle dependencies | grep "javax."   # Gradle
    
  • 引入 spring-boot-properties-migrator(runtime scope,用于首次升级检测)

阶段三:代码修改

  • 替换 Jackson 核心类导入com.fasterxml.jackson.core/databind/dataformat.*tools.jackson.*
  • 替换 Jackson2ObjectMapperBuilder → JsonMapper.builder()
     复制代码// 旧
    Jackson2ObjectMapperBuilder.json().build()
    // 新
    JsonMapper.builder().build()
    
  • 检查所有 Jackson2ObjectMapperBuilderCustomizerJsonMapperBuilderCustomizer
  • 将 Jackson 2 注解/基类迁移到 Jackson 3 对应物(类名有变化):
    • @JsonComponent@JacksonComponent
    • JsonObjectSerializer<T>ObjectValueSerializer<T>
    • JsonObjectDeserializer<T>ObjectValueDeserializer<T>
    • @JsonMixin@JacksonMixin
    • JsonComponentModuleJacksonComponentModule
    • 模块坐标从 spring-boot-jackson2spring-boot-jackson
  • 替换 EnvironmentPostProcessor 导入
     复制代码// 旧
    import org.springframework.boot.env.EnvironmentPostProcessor;
    // 新
    import org.springframework.boot.EnvironmentPostProcessor;
    
  • 检查 RestTemplateBuilder 中的 .rootUri().baseUri()
  • 检查 AntPathMatcher 使用 → 替换为 PathPatternParser
  • 如果使用 SpringFox → 迁移到 SpringDoc OpenAPI
  • 检查自定义 SessionProperties.determineTimeout() 调用
  • 检查自定义 Health 模块中是否使用了 SimpleStatusAggregator / HttpCodeStatusMapper / SimpleHttpCodeStatusMapper

阶段四:配置修改

  • 移除 spring.mvc.pathmatch.matching-strategy=ant_path_matcher
  • 移除所有 server.undertow.* 配置
  • 确认 spring.factories 中的自动配置已迁移到 AutoConfiguration.imports

阶段五:启动验证

  • 首次启动,观察 PropertiesMigrationListener 输出的迁移报告
  • 修复所有 WARN/ERROR 级别的配置迁移提示
  • 全量运行单元测试和集成测试
  • 验证 Jackson 序列化/反序列化行为一致
  • 移除 spring-boot-properties-migrator 依赖(迁移完成后)

Spring Cloud 兼容矩阵

升级 Boot 4 的同学,Spring Cloud 也得跟着升。别搞错版本对应关系:

Spring Cloud 版本Spring Boot 版本Spring Framework状态
2025.0.x4.0.x / 4.1.x7.0.x 兼容
2024.0.x3.4.x6.2.x 不兼容 Boot 4
2023.0.x (Spring Cloud AWS 等)3.2.x / 3.3.x6.1.x 不兼容 Boot 4

总结:三句话讲清楚 Boot 3→4 升级

Spring Boot 3→4 的升级相比 2→3 友好得多。核心影响面集中在三个领域:

  1. Jackson 3 包名变更:核心类从 com.fasterxml.jacksontools.jackson,这是最大的代码改动量
  2. Undertow 被移除:必须切换 Web 容器,但对于大多数已使用 Tomcat 的项目零影响
  3. 一批 API 的弃用与重命名spring-boot-properties-migrator 能帮你自动发现和处理

建议的升级策略:先引入 migrator → 修正所有编译错误 → 启动验证 → 运行测试 → 移除 migrator,五步完成升级。


写在最后

如果这篇文章帮你少踩了一个坑,点个赞再走呗

有什么升级过程中遇到的问题,欢迎在评论区交流,我会一一回复。


热门栏目