兄弟们,升级 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
接下来进入正文,每一项都附带源码证据 + 改写示例,大家可以对照自己的项目逐项排查。
源码证据:starter/spring-boot-starter-parent/build.gradle
复制代码delegate."java.version"('17')
Spring Boot 4 的 JDK 17 是硬性编译基线,不可降级。同时,官方强烈推荐使用 JDK 25,以充分利用:
| JDK 特性 | 最低版本 | 在 Spring Boot 4 中的应用 |
|---|---|---|
| 虚拟线程 GA | JDK 21 | spring.threads.virtual.enabled=true 的前置条件 |
| Record 类 | JDK 16 (GA 17) | 配置属性绑定、DTO 简化 |
| Sealed Class | JDK 17 | 模块化自动配置的类型层级 |
| Pattern Matching for switch | JDK 21 | 框架内部条件判断简化 |
| Scoped Values | JDK 21 (GA 25) | 替代 ThreadLocal 的上下文传递(4.1 增强) |
| Stream Gatherers | JDK 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
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 事务管理(UserTransaction、TransactionManager) |
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>
这是 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.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.* 保持不变
在 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 默认(响应式容器)
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 自定义 UndertowBuilderCustomizer | TomcatServletWebServerFactoryCustomizer 或 JettyServletWebServerFactoryCustomizer |
源码证据: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;
}
源码证据: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 将 EnvironmentPostProcessor 从 org.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.bootDeferredLogFactory(延迟日志工厂)和 ConfigurableBootstrapContext(可配置的启动上下文)Ordered 接口或标注 @Order 注解(与旧接口相同)源码证据: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();
源码证据: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 机制。
源码证据: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 实现)。
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(ApplicationContextInitializer、ApplicationListener、FailureAnalyzer 等),但自动配置类已不再从 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

不知道自己项目要改哪些?跟着这棵决策树走一遍:
复制代码java -version # 确认版本
复制代码<!-- Maven parent -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.0</version>
</parent>
复制代码plugins {
id 'org.springframework.boot' version '4.1.0'
}
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,用于首次升级检测)com.fasterxml.jackson.core/databind/dataformat.* → tools.jackson.*) 复制代码// 旧
Jackson2ObjectMapperBuilder.json().build()
// 新
JsonMapper.builder().build()
Jackson2ObjectMapperBuilderCustomizer → JsonMapperBuilderCustomizer@JsonComponent → @JacksonComponentJsonObjectSerializer<T> → ObjectValueSerializer<T>JsonObjectDeserializer<T> → ObjectValueDeserializer<T>@JsonMixin → @JacksonMixinJsonComponentModule → JacksonComponentModulespring-boot-jackson2 → spring-boot-jackson 复制代码// 旧
import org.springframework.boot.env.EnvironmentPostProcessor;
// 新
import org.springframework.boot.EnvironmentPostProcessor;
.rootUri() → .baseUri()spring.mvc.pathmatch.matching-strategy=ant_path_matcherserver.undertow.* 配置spring.factories 中的自动配置已迁移到 AutoConfiguration.importsPropertiesMigrationListener 输出的迁移报告spring-boot-properties-migrator 依赖(迁移完成后)升级 Boot 4 的同学,Spring Cloud 也得跟着升。别搞错版本对应关系:
| Spring Cloud 版本 | Spring Boot 版本 | Spring Framework | 状态 |
|---|---|---|---|
| 2025.0.x | 4.0.x / 4.1.x | 7.0.x | 兼容 |
| 2024.0.x | 3.4.x | 6.2.x | 不兼容 Boot 4 |
| 2023.0.x (Spring Cloud AWS 等) | 3.2.x / 3.3.x | 6.1.x | 不兼容 Boot 4 |
Spring Boot 3→4 的升级相比 2→3 友好得多。核心影响面集中在三个领域:
com.fasterxml.jackson → tools.jackson,这是最大的代码改动量spring-boot-properties-migrator 能帮你自动发现和处理建议的升级策略:先引入 migrator → 修正所有编译错误 → 启动验证 → 运行测试 → 移除 migrator,五步完成升级。
如果这篇文章帮你少踩了一个坑,点个赞再走呗
有什么升级过程中遇到的问题,欢迎在评论区交流,我会一一回复。