2026-07-24
JAVA
0

目录

Spring Boot 4 来了:这波更新到底改了啥?
事情是这样的
为什么版本号敢跳 4?
先聊最痛的部分:依赖大清洗
Undertow 被砍了
Jackson 2 → 3:包名都换了
Hibernate 6 → 7
Resilience4j 不再是必需品
十项核心新功能详解(干货区)
一、JSpecify 空安全——以后 NPE 在编译期就爆
二、HTTP Interface Client——一行配置搞定 HTTP 调用
三、BeanRegistrar——告别反射式启动
四、原生 API 版本控制——终于不用各玩各了
五、内置弹性容错——Resilience4j 可以下岗了
六、Spring Data AOT——查询编译期预生成
七、OpenTelemetry 原生集成
八、REST Test Client——测试不用再换三套 API
九、JMS Client API——清爽的消息发送
十、模块化重构:一个大 Jar 拆成 70+ 模块
升级踩坑指南
最痛的 Top 5
官方推荐升级路径
迁移时间预估
Spring Boot 4.1 又加了什么?
Spring gRPC 支持
HTTP Client SSRF 防护
可观测性增强
Log4j 文件轮转
Spring AI 2.0
生态全家桶同步升级
到底要不要升?
总结

Spring Boot 4 来了:这波更新到底改了啥?

版本号从 3 跳到 4,底层 Framework 从 6 跳到 7。
这不是一次小修小补,而是把整个地基都换了。


事情是这样的

先问一个问题:你用的 Spring Boot 是啥版本?

如果你还在 3.x 甚至 2.x 上摸鱼,那这篇文章得好好看看。

事情是这样的。上个月有个兄弟问我:"Spring Boot 4 出了,要不要升?"我说你先别急,让我看看它到底改了啥再说。

结果一看,好家伙——这特么不是加几个新注解的升级,这是把房子拆了重盖。

Spring Boot 4.0 是 2025 年 11 月 30 号发布的,底层是 Spring Framework 7。到现在最新稳定版已经是 4.1.0(2026 年 6 月)。与此同时,Spring Boot 3.5.x 在 2026 年 6 月 30 号 OSS 支持已经正式结束了。

Spring 团队的意思很明确:别在 3.x 上磨蹭了,赶紧过来。


技术基线对比图

为什么版本号敢跳 4?

先捋一下版本号的逻辑。

Spring Boot 3.x 底层是 Spring Framework 6(2022 年底发布),Spring Boot 4.x 底层是 Spring Framework 7(2025 年底发布)。

从 6 到 7 这跳得有多大?这么说吧:

对比项Spring Boot 3.xSpring Boot 4.x
Java 基线Java 17Java 17 最低,推荐 Java 21/25
Spring Framework6.x7.x
嵌入式服务器Tomcat 10 / Undertow / JettyTomcat 11+ / Jetty(Undertow 滚了)
Jackson2.x(com.fasterxml)3.x(tools.jackson)
Hibernate67
Jakarta EE1011
Servlet6.06.1
Micrometer1.x2.x
模块数1个大jar70+ 独立模块

看到没有?从 Hibernate 到 Jackson 到 Servlet 到嵌入式服务器,全线换新。

这就好比你买车——3.x 是给你换了新发动机,4.x 是连底盘、变速箱、轮毂、车机全换了。


十大新功能速览

先聊最痛的部分:依赖大清洗

Undertow 被砍了

如果你项目用的嵌入式服务器是 Undertow,那你是逃不掉了——Undertow 不支持 Servlet 6.1,直接被 Spring 7 踢出局。

得切到 Tomcat 11+ 或者 Jetty。Tomcat 11 是官方推荐方案。

Jackson 2 → 3:包名都换了

com.fasterxml.jackson 变成了 tools.jackson

所有 import 要改。所有自定义序列化器、反序列化器要重写。Jackson 3 的配置模型改成不可变的了,以前用 ObjectMapper 各种 setter 配置的方式也得跟着变。

这可能是 3.x 升 4.x 过程中最费时的部分,没有之一。

Hibernate 6 → 7

同样不是小版本升级。Hibernate 7 去掉了一堆废弃 API,语义查询那块改动也比较大。如果你项目里有 Hibernate 自定义类型、Interceptor、EventListener,报错大概率出现在这里。

Resilience4j 不再是必需品

这个后面细聊,但先提一嘴——之前做重试、限流得引入 Resilience4j,现在 Spring 内置了,所以 Resilience4j 不再是必选项了。但你要继续用也可以,Spring 7 还是兼容的。

十项核心新功能详解(干货区)

一、JSpecify 空安全——以后 NPE 在编译期就爆

淦。你以为 NullPointerException 这玩意儿还只是在运行时才炸?

Spring 3.x 的时候,空安全全靠各家野路子——Spring 自己搞了 org.springframework.lang.Nullable,JetBrains 搞了 org.jetbrains.annotations.Nullable,Lombok 又来一套。IDE 支持是有的,但静态分析一塌糊涂,根本没法统一。

Spring 4 直接一锤定音:全换成 JSpecifyorg.jspecify.annotations)。

用法很简单,在 package-info.java 里写一行:

java
@NullMarked package com.example.myapp;

然后这个包里所有方法的参数、返回值默认就是 non-null。只有显式标了 @Nullable 的才允许为空。

java
public User findById(Long id) { // id 不能是 null,编译器会检查 return userRepository.findById(id).orElseThrow(); } // 允许为空的地方要显式声明 public List<User> search(@Nullable String name) { if (name == null) { return userRepository.findAll(); } return userRepository.findByName(name); }

也就是说,以前你在 IDE 里看到的灰色警告,现在直接变成编译错误。配合 NullAway 这种静态分析工具,可以在 CI 阶段就卡住 NPE,而不是等跑到线上才炸。

对 Kotlin 用户来说也是利好——Spring 的 nullability 信息传过去后,Kotlin 不用再到处写 !! 了。

说人话就是:以前写代码像闭着眼睛走夜路,现在给你发了把手电筒。

二、HTTP Interface Client——一行配置搞定 HTTP 调用

用过 Feign 的兄弟都懂,声明式 HTTP 客户端确实方便——写个接口,加几个注解,Spring 自动生成实现。

之前 Spring 其实也有 @HttpExchange,但你需要手动配置 HttpServiceProxyFactory

java
// 以前:手动配置一大串 @Bean public TodoService todoService(RestClient.Builder builder) { var restClient = builder.baseUrl("https://api.example.com").build(); var adapter = RestClientAdapter.create(restClient); var factory = HttpServiceProxyFactory.builderFor(adapter).build(); return factory.createClient(TodoService.class); }

Spring Boot 4 直接干了:@ImportHttpServices,一行注解就够:

java
@Configuration @ImportHttpServices(TodoService.class) public class HttpClientConfig { // 没了,就这 } @HttpExchange(url = "https://jsonplaceholder.typicode.com") public interface TodoService { @GetExchange("/todos") List<Todo> getAllTodos(); @GetExchange("/todos/{id}") Todo getTodoById(@PathVariable Long id); @PostExchange("/todos") Todo createTodo(@RequestBody Todo todo); }

接口自动变成 Bean,直接 @Autowired 注入就能用。类型安全、编译期检查,不用再手写 RestTemplate 调用。

这玩意儿跟 Feign 比怎么样?功能上差不多,但胜在 零外部依赖——不需要引入 OpenFeign 的依赖和 Spring Cloud 那一套。适合那些不想再堆技术栈的新项目。

三、BeanRegistrar——告别反射式启动

这特么是这波更新里最被低估的改动

Spring Boot 3.x 的启动过程是怎么工作的?Spring 通过反射扫描你的字节码,找到 @Configuration@Bean@ConditionalOnClass,然后一个一个解析。所有这些步骤都发生在运行时

几十上百个条件注解,每个都要加载类、检查类路径、评估表达式——这就是为什么 Spring Boot 应用启动慢的核心原因之一。

Spring 4 推出了 BeanRegistrar

java
public class AppRegistrar implements BeanRegistrar { @Override public void register(BeanRegistry registry, Environment env) { String dbType = env.getProperty("app.db-type", "h2"); switch (dbType) { case "mysql" -> registry.registerBean("dataSource", MysqlDataSource.class, spec -> spec.supplier(MysqlDataSource::new)); case "h2" -> registry.registerBean("dataSource", H2DataSource.class, spec -> spec.supplier(H2DataSource::new)); } } }

看到区别了吗?没有反射、没有字节码扫描、没有 @ConditionalOnClass。Bean 的注册逻辑是在编译期就由 AOT 处理器处理好的,运行时就只管执行。

实际收益:结合模块化改动,一个典型微服务的启动时间可以快 50%-70%。在 K8s 上冷启动时,这不只是体验问题——这他妈是钱的问题。

四、原生 API 版本控制——终于不用各玩各了

API 版本管理这个需求,在之前的 Spring 里一直是个灰色地带。

有的团队用 URL 路径 /api/v1/users/api/v2/users,每个 Controller 写两套方法,@RequestMapping 加正则匹配。 有的团队用自定义 Header,自己写拦截器解析 Accept-Version。 有的团队在 Query Parameter 里传 ?version=1

结果就是每个项目一套搞法,OpenAPI 文档对不上,前端调用靠猜。

Spring 7 终于把这事儿内置了:

java
@RestController @RequestMapping("/api/users") public class UserController { @GetMapping(version = "1.0") public UserDTOv1 getUserV1(@PathVariable Long id) { return new UserDTOv1(id, user.getName()); } @GetMapping(version = "2.0") public UserDTOv2 getUserV2(@PathVariable Long id) { return new UserDTOv2(id, user.getFirstName(), user.getLastName()); } }

支持三种策略:

  • Media Type 参数Accept: application/json;version=1.0
  • 路径前缀/api/v1/users
  • Query Parameter/api/users?version=1

还支持 RFC 兼容的 Deprecation Header,通知客户端某个版本什么时候下线。

java
@Configuration public class ApiVersioningConfig implements WebMvcConfigurer { @Override public void configureApiVersioning(ApiVersionConfigurer configurer) { configurer .useMediaTypeParameterVersioning() .deprecateVersion("1.0", "2026-12-31", "Use version 2.0 instead"); } }

说人话就是:不用再自己写拦截器了,框架帮你干了。

五、内置弹性容错——Resilience4j 可以下岗了

这是做微服务的兄弟们最该关注的更新。

之前想在 Spring 里做重试、限流、熔断,得搞 Resilience4j。这东西本身是好东西,但有个老大难问题——异步重试时上下文丢失

Resilience4j 的重试在单独的线程池里跑,SecurityContext、TraceContext、MDC 全丢了。每个集成 Spring Cloud 的项目都在踩这个坑。

Spring 7 直接把容错能力内置了:

@Retryable——原生重试

java
@Service public class PaymentService { @Retryable( maxAttempts = 4, backoff = @Backoff(delay = 500, multiplier = 2.0, jitter = 100) ) public String fetchData(String id) { return externalApi.getData(id); } }

AOP 代理在同一个线程里重试,Security 上下文、Trace 上下文、MDC 全都在,不会丢。支持指数退避 + jitter,防止惊群效应。

@ConcurrencyLimit——并发控制

java
@Service public class ReportService { @ConcurrencyLimit(2) // 最多 2 个并发 public String performHeavyOperation(String taskId) { return heavyComputation(taskId); } }

不需要引入外部限流库,一个注解搞定。

不过也要说个大实话:内置的只是重试和并发控制,没有完整的熔断器和舱壁隔离。如果你需要 Circuit Breaker、Bulkhead 这些高级特性,Resilience4j 仍然是你最好的选择。但日常 80% 的微服务场景,重试 + 限流已经够用了。

六、Spring Data AOT——查询编译期预生成

这块有点底层,但对性能影响很大。

Spring Data JPA 的核心理念是"方法名解析成 SQL"——你写个 findByNameContainingIgnoreCase,它给你拼出 WHERE name LIKE %?%

这个过程在 Spring 3.x 里是在运行时完成的。每次项目启动,Spring Data 都要解析所有 Repository 接口的方法名,生成查询,然后缓存起来。

Spring Data AOT 把这个过程搬到了编译期

java
public interface CoffeeRepository extends CrudRepository<Coffee, Long> { // AOT 编译期生成 SQL List<Coffee> findByNameContainingIgnoreCase(String name); List<Coffee> findByRoastLevelAndOrigin(String roastLevel, String origin); @Query("SELECT * FROM coffee WHERE price < :maxPrice ORDER BY price") List<Coffee> findAffordableCoffees(BigDecimal maxPrice); }

编译时,AOT 处理器会解析方法名、生成对应的 SQL 源码,放在 target/spring-aot/ 目录下。启动时直接加载预生成代码,省掉了方法名解析和查询构建的时间

给你的项目带来的收益:

  • 启动速度提高 50%-70%
  • 运行时内存占用减少
  • 容器场景下冷启动时间大幅缩短

七、OpenTelemetry 原生集成

可观测性这块,Spring 之前一直靠 Micrometer + 手动配置 Exporter。

3.x 的 Micrometer Tracing 已经有了基本能力,但要把 Trace、Metrics、Logs 打通,还是得自己去搭 OpenTelemetry Collector,配置 Exporter,写一堆 config。

Spring Boot 4 直接给了 spring-boot-starter-opentelemetry

xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-opentelemetry</artifactId> </dependency>

配置也很简单:

yaml
spring: application: name: my-service management: tracing: sampling: probability: 1.0 otlp: tracing: endpoint: http://localhost:4318/v1/traces

搞定后,HTTP 请求、数据库调用、日志全部自动关联 Trace ID:

2026-07-22 10:30:45 INFO [traceId=abc123, spanId=def456] Processing order...

要加自定义 Span 的话,用 @Observed

java
@Service public class OrderService { @Observed(name = "order.process", contextualName = "processOrder") public Order processOrder(OrderRequest request) { return orderRepository.save(createOrder(request)); } }

跟之前比,最大的区别是不用自己搭 OTel Collector,直接 OTLP 协议打到后端(Jaeger、Grafana Tempo、SigNoz 都支持),一套配置全自动。

八、REST Test Client——测试不用再换三套 API

做 Spring 测试的老哥应该都有这个经历:

  • 写单元测试用 MockMvc
  • 写集成测试用 TestRestTemplate
  • 写 WebFlux 测试用 WebTestClient

三个 API,三种风格,脑子都要换三次。

Spring Boot 4 的 RestTestClient 一统江湖:

java
// 单元测试——绑定 Controller(快速、隔离) @ExtendWith(MockitoExtension.class) class TodoControllerTest { private RestTestClient client; @BeforeEach void setUp() { client = RestTestClient.bindToController( new TodoController(todoService) ).build(); } @Test void shouldGetAllTodos() { when(todoService.findAll()) .thenReturn(List.of(new Todo(1L, "Learn Spring", false))); client.get() .uri("/api/todos") .exchange() .expectStatus().isOk() .expectBody() .jsonPath("$[0].title").isEqualTo("Learn Spring"); } }
java
// E2E 测试——绑定真实服务器 @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class TodoIntegrationTest { private RestTestClient client; @BeforeEach void setUp() { client = RestTestClient.bindToServer() .baseUrl("http://localhost:" + port) .build(); } @Test void shouldCreateTodo() { client.post() .uri("/api/todos") .contentType(MediaType.APPLICATION_JSON) .bodyValue(new Todo(null, "Integration test", false)) .exchange() .expectStatus().isCreated(); } }

支持 5 种绑定方式:bindToControllerbindToMockMvcbindToApplicationContextbindToServerbindToRouterFunction

说人话就是:以后写测试不用记三套 API 了,一套搞定从单元到 E2E。

九、JMS Client API——清爽的消息发送

如果你项目里用到了 JMS(ActiveMQ Artemis 之类的),以前用 JmsTemplate 发消息是这样:

java
jmsTemplate.convertAndSend("orders.queue", order);

新版 JMS Client API 采用了 Fluent 风格:

java
@Service public class OrderMessagingService { private final JmsClient jmsClient; // 基础发送 public void sendOrder(Order order) { jmsClient.send("orders.queue").withBody(order); } // 带优先级和 TTL public void sendPriorityOrder(Order order) { jmsClient.send("orders.queue") .withPriority(9) .withTimeToLive(Duration.ofMinutes(5)) .withBody(order); } // Request-Reply 模式 public OrderConfirmation processOrder(Order order) { return jmsClient.requestAndReceive("orders.queue") .withBody(order) .convertTo(OrderConfirmation.class); } }

清爽很多,而且支持 7 种消息模式。不过 JmsTemplate 仍然保留,不强制迁移。

十、模块化重构:一个大 Jar 拆成 70+ 模块

这是架构级别的改动,你可能写代码时感受不到,但它带来的收益是实打实的。

Spring Boot 3.xspring-boot-autoconfigure 一个大 Jar 里装了所有东西——JDBC、Kafka、Redis、MongoDB、WebSocket……哪怕你只用了数据库,Maven 还是把所有 autoconfigure 类都拉到 classpath 里。

Spring Boot 4.x:拆成 70+ 独立模块:

spring-boot-autoconfigure-jdbc spring-boot-autoconfigure-kafka spring-boot-autoconfigure-redis spring-boot-autoconfigure-web-servlet spring-boot-autoconfigure-webflux spring-boot-autoconfigure-mongodb ...

你声明什么 Starter,就只拉对应的 autoconfigure 模块。

直接收益:

  • GraalVM AOT 更快:编译器不用处理一大堆 @ConditionalOnClass 评估
  • Native Image 更小:没用到的代码路径永远不会被打进去
  • 启动更快:类路径扫描的东西少了

在 K8s 上跑微服务的兄弟都懂——冷启动时间每少一秒,扩缩容的体验就好一个档次。

升级踩坑指南

破坏性变更清单 说了这么多好东西,也该说说升级要踩的坑了。毕竟从 3.x 到 4.x,跟之前 2.x 到 3.x 一样,不是加个版本号就能跑的。

最痛的 Top 5

第一名:Jackson 2 → 3

  • 包名从 com.fasterxml.jackson 变成 tools.jackson
  • 所有 import 要改,IDE 全局替换能解决大部分,但自定义序列化器得手动重写
  • Jackson 3 的配置模型是 immutable 的,ObjectMapper 的 setter 要改

第二名:Undertow 移除

  • 如果你用的嵌入式服务器是 Undertow,必须换 Tomcat 11+ 或 Jetty
  • 排查有没有 Undertow 特有的配置项

第三名:Hibernate 6 → 7

  • 废弃 API 移除
  • 自定义类型、Interceptor、EventListener 可能编译失败

第四名:Spring Security 6 → 7

  • OAuth2 配置有变动
  • 之前用 Legacy OAuth2 auto-configuration 的,得切到 Spring Authorization Server

第五名:配置属性重命名

  • management.tracing.enabledmanagement.tracing.export.enabled
  • spring.dao.exceptiontranslation.enabledspring.persistence.exceptiontranslation.enabled

官方推荐升级路径

还在 Boot 2.x? → 先升 3.5(清掉所有 deprecation) → 再升 4.x 已在 Boot 3.x? → 升到最新 3.5.x(清 deprecation) → 升 4.x 新项目? → 直接 4.1.0,别犹豫

官方说了:不要跨版本跳。3.3.x 直跳 4.x 的方式,编译可能通过但运行时一堆问题。

迁移时间预估

别想着周末加个班就能搞定。一个中等规模的微服务(几十个模块、几百个 API),保守估计:

阶段时间
依赖分析 + 影响评估1-2 天
Jackson 3 迁移1-3 天
Hibernate 7 适配1-2 天
Security 配置更新1 天
测试 + 修复2-5 天
灰度发布1-2 天

加起来 1-2 周,还是在测试覆盖率高、没有太多自定义配置的前提下。

但话说回来,从 3.x 升 4.x 的收益,对于做微服务 + K8s 的团队来说,绝对值这个时间。

Spring Boot 4.1 又加了什么?

前面聊的都是 4.0 的基础功能。4.1.0(2026年6月发布)在此基础上再加了 5 个东西:

Spring gRPC 支持

写 gRPC 服务器和客户端不再需要自己搞 Protobuf + Netty 那一套。支持 Netty 独立部署或通过 Servlet over HTTP/2 集成。

HTTP Client SSRF 防护

InetAddressFilter 可以配置黑名单/白名单,限制出站请求能连的 IP 段,防止 SSRF 攻击。

yaml
spring: http: client: ssrf: inet-address-filter: allowed: "10.0.0.0/8" blocked: "169.254.0.0/16"

可观测性增强

@Async 方法现在自动传播追踪上下文,不再跨线程丢 Trace 了。

Log4j 文件轮转

Log4j 支持可配置的轮转策略:大小、时间、大小+时间、Cron 表达式。Logback 那边之前早就有轮转配置,Log4j 用户终于等到了。

Spring AI 2.0

基于 Spring Boot 4.0 基线,引入 MCP SDK 2.0、@McpTool 注解模式、Agentic 改进。想搞 AI Agent 的兄弟可以关注。

生态全家桶同步升级

Spring Boot 4 不只是一家升,整个 Spring 生态全系联动:

项目3.x 对应版本4.x 对应版本
Spring Data2024.x2025.1 / 2026.0
Spring Security6.x7.x
Spring Kafka3.x4.x
Spring Integration6.x7.x
Spring AI1.x2.0
Spring Modulith1.x2.x
Spring Batch5.x6.x
Spring AMQP3.x4.x
Spring Session3.x4.x
Spring Cloud2024.x待确认,建议升前查兼容表

如果你的项目依赖 Spring Cloud Alibaba(就像咱们的 nsw-project 一样),等 Spring Cloud Alibaba 出了对应 4.x 的版本再升,不要独自冲锋。

到底要不要升?

如果你问我个人的看法——分情况

新项目:直接 Spring Boot 4.1.0 + Java 21。没任何理由在新项目上还用 3.x。启动快、内置容错、原生 OTel、API 版本控制,这些都是白捡的优势。

已有 Boot 3.x 项目:等你的迭代节奏到了大版本窗口期再升。先把当前版本的 deprecation 清干净,升到 3.5.x,再跳 4.x。优先确保 Spring Cloud Alibaba 的兼容性

还在 Boot 2.x 的老项目:你有两个 migration 要走,别想着一步到位。先 2→3,再 3→4,每一步都要走稳。建议先在内网工具/低流量服务上试点,练熟了再动核心服务。

不升级的代价:Boot 3.5.x 的 OSS 支持在 2026 年 6 月 30 号已经结束。也就是说,不会再收到安全补丁和 bug 修复。如果你还在生产环境跑 3.5 以下的版本,要么升,要么买商业支持。安全漏洞不会等你准备好才来。

总结

Spring Boot 4 这波更新,不是那种"加了几个注解、性能优化 10%"的小升版。它是把 Spring 从一个"运行时要反射扫描、启动要半分钟、容错靠外部依赖"的传统框架,往"编译期搞定、启动秒级、原生支持云原生"的方向彻底转型。

核心变化就这几句话:

  • 模块化 → 启动更快、镜像更小
  • BeanRegistrar + AOT → 编译期干活,不等启动
  • 内置容错 → 不再为简单的重试引入外部依赖
  • JSpecify → NPE 从线上提到编译期
  • Undertow 滚了、Jackson 3 来了 → 升级要付出代价

最实在的忠告:依赖清洗是这次升级最痛的部分,先评估影响面,再排计划,不要盲目开搞。

这玩意儿属于"早搞早享受,但不做好功课硬搞就是找虐"的典型。

还没细看的兄弟建议找个周末,建个分支跑一遍编译再决定。体验提升是真的,代价也是真的。


本文基于 Spring 官方 Release Notes、Dan Vega 博客、多位技术博主分析以及 Spring 4.1 发布公告整理。 有用的话点个赞,有问题下面留言。

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:JACK WEI

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!