Spring Boot 4 和 Spring Framework 7:Java 微服务快速安全的新时代
Spring Boot 4.0(2025 年 11 月发布)和 Spring Framework 7.0 一起,算得上 Java 生态这几年最有分量的一次升级。不是小修小补,而是在模块化、空值安全、声明式 HTTP 客户端、弹性模式这些核心位置动了刀。
下面逐个拆。
最低要求:拥抱现代性
先说硬门槛。Java 最低要求还是 Java 17,但强烈建议用 Java 21 或更高(最好是 Java 25),因为 Virtual Threads 在这个版本已经足够成熟,在不少场景下可以直接替代传统的响应式编程(WebFlux)。Jakarta EE 11 对齐完成,Servlet 6.1、JPA 3.2、Bean Validation 3.1 都进来了。Kotlin 需要 2.2 或更高。GraalVM 24+ 完全支持,原生镜像生成优化了不少。
性能的巨大飞跃:模块化和 AOT
模块化
以前 spring-boot-autoconfigure 是一个巨大的工件,不管你用不用,几乎所有东西的配置逻辑都在里面,产生了大量 "classpath noise"。
Spring Boot 4 把这个模块拆成了更小、更专注的工件,自动配置分散在专门的模块里,按需加载。效果是启动更快(扫描的代码少了),内存占用更低(只加载真正需要的),IDE 建议更精确,GraalVM 原生镜像生成也更高效。
AOT 编译和 GraalVM
Spring Boot 4 完全对齐 GraalVM 24+。AOT(Ahead-of-Time)处理做了显著优化:编译时间更短,启动时内存占用更低,静态分析更强(能消掉更多死代码),reflection hints 兼容性改善。
新的 @ConfigurationPropertiesSource 注解允许更细粒度的模块化,只有相关的配置属性才会被处理。
空值安全:NPE 在编译时就该死
Java 里的 null 处理一直是生产事故的常客。Spring Framework 7 和 Spring Boot 4 在整个产品组合中采用了 JSpecify 作为空值安全标准。
JSpecify 是 Google、JetBrains、Meta、Oracle 等联合支持的协作标准,用注解明确标记值是否可以为 null。@Nullable 表示可能缺失,@NonNull 表示绝不为 null,@NullMarked 给整个包建立默认规则:除非另有说明,一切都是 NonNull。
@NullMarked 的实际效果
创建一个 package-info.java,把整个包标记为空值安全:
// src/main/java/com/tuempresa/servicio/package-info.java
@org.jspecify.annotations.NullMarked
package com.tuempresa.servicio;之后你的 IDE(IntelliJ IDEA 2025.3+ 支持)会在你尝试在期望非空值的地方使用可能为 null 的值时,当场报错。开发时就拦住,而不是等到生产环境抛 NPE。
@NullMarked
package com.ejemplo.usuarios;
public class UsuarioService {
// IDE 会在你尝试传递 null 时警告
public Usuario crearUsuario(@NonNull String nombre, @Nullable String apellido) {
// nombre 永不为 null - 可以直接安全使用
String nombreCompleto = nombre.toUpperCase();
// apellido 可能为 null - 你必须检查
if (apellido != null) {
nombreCompleto += " " + apellido.toUpperCase();
}
return new Usuario(nombreCompleto);
}
}声明式 HTTP 客户端:Feign 的"杀手"
Spring Boot 4 内置了声明式 HTTP 客户端,service-to-service 通信不再需要 Spring Cloud OpenFeign 这类外部依赖。
RestTemplate 在 Spring Framework 7 中正式弃用,未来版本会移除。代码冗长、难测试、不利用现代 Java 特性,是时候放手了。
接替它的是 RestClient(现代替代品,流畅的 builder 风格 API)和 @HttpExchange 声明式客户端。后者更值得关注:
package com.tuempresa.clients;
import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.PostExchange;
import org.springframework.web.service.annotation.HttpExchange;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
@HttpExchange("/api/productos")
public interface ProductoClient {
@GetExchange("/{id}")
Producto obtenerProducto(@PathVariable("id") String id);
@GetExchange
List<Producto> listarProductos();
@PostExchange
Producto crearProducto(@RequestBody Producto producto);
}配置客户端:
@Configuration
public class ClientConfig {
@Bean
public ProductoClient productoClient(RestClient.Builder builder) {
RestClient restClient = builder
.baseUrl("https://api.ejemplo.com")
.build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory
.builderFor(RestClientAdapter.create(restClient))
.build();
return factory.createClient(ProductoClient.class);
}
}定义接口就够了,不用写样板代码。接口天然容易 mock,类型安全,不需要额外依赖。Spring Boot 4 还改进了自动配置,通过 clientType 属性可以在 RestClient(默认)和 WebClient(响应式场景)之间切换,客户端代码不用改。
弹性和 API 版本控制
原生弹性
以前要用 Spring Retry 这种外部项目才能做的事,现在内置到 Spring Framework 7 了:
@Service
@EnableResilientMethods
public class PagoService {
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000))
public PagoRespuesta procesarPago(PagoRequest request) {
// 如果失败,最多重试 3 次,等待 1 秒
return pagoGateway.procesar(request);
}
@ConcurrencyLimit(maxConcurrency = 10)
public Report generarReporte() {
// 最多 10 个并发调用
return reportService.generar();
}
}@Retryable 做重试,@ConcurrencyLimit 限制并发,@EnableResilientMethods 激活这些注解。
原生 API 版本控制
REST API 版本控制以前各种第三方方案混战。Spring Framework 7 把 version 属性直接加到了 @RequestMapping 及其变体里:
@RestController
@RequestMapping("/api/pedidos")
public class PedidoController {
// 版本 1:简单响应
@GetMapping(version = "1", produces = MediaType.APPLICATION_JSON_VALUE)
public List<PedidoV1> getPedidosV1() {
return pedidoService.obtenerPedidosSimples();
}
// 版本 2:带有元数据的丰富响应
@GetMapping(version = "2", produces = MediaType.APPLICATION_JSON_VALUE)
public PedidoResponseV2 getPedidosV2() {
return pedidoService.obtenerPedidosCompletos();
}
}版本控制策略集中配置,可以在不改 controller 的情况下切换策略(路径、header、查询参数):
@Configuration
public class ApiVersioningConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
// 基于 header 的策略
configurer.apiVersioning(builder -> builder
.strategy(VersionStrategy.HEADER)
.headerName("API-Version")
);
// 或基于路径:/v1/pedidos, /v2/pedidos
// 或基于查询参数:/pedidos?version=1
}
}可观测性
Spring Boot 4 在可观测性上投入不少。Micrometer 2.0 更新了,原生 OpenTelemetry starter 内置了,日志、指标和追踪自动关联。
@Observed 注解给任何方法自动生成指标和追踪:
@Service
public class InventarioService {
@Observed(name = "inventario.verificar", contextualName = "verificarDisponibilidad")
public boolean verificarDisponibilidad(String productoId) {
// 自动生成以下指标:
// - 执行时间
// - 调用次数
// - 错误率
return inventarioRepository.existeStock(productoId);
}
}Actuator 现在对 SSL 证书做了自动监控。证书快过期的时候(默认 14-30 天内),/actuator/health 会明确报告:
{
"status": "UP",
"components": {
"ssl": {
"status": "WARNING",
"details": {
"certificate": "api.ejemplo.com",
"expiresIn": "12 days",
"expiryDate": "2025-12-05"
}
}
}
}生产环境证书意外过期这种事,提前两周就能收到预警。
Client 模式:Template 的接班人
如果你用过 Spring,一定用过各种 Template(JdbcTemplate、RestTemplate、JmsTemplate)。Spring Framework 7 正在从 Template Method 模式迁移到基于 builder 和函数式接口的 Client 模式。
RestTemplate 已弃用,由 RestClient 和 @HttpExchange 接替。JdbcTemplate 和 JdbcClient 共存。JmsClient 是新增的。
JdbcClient
JdbcClient 用 builder 风格消掉了 JdbcTemplate 的冗长。以前写一个查询:
public List<Persona> findAll() {
return jdbcTemplate.query(
"SELECT id, nombre, edad FROM persona",
new RowMapper<Persona>() {
@Override
public Persona mapRow(ResultSet rs, int rowNum) throws SQLException {
Persona p = new Persona();
p.setId(rs.getLong("id"));
p.setNombre(rs.getString("nombre"));
p.setEdad(rs.getInt("edad"));
return p;
}
}
);
}现在:
public List<Persona> findAll() {
return jdbcClient.sql("SELECT id, nombre, edad FROM persona")
.query((rs, rowNum) -> new Persona(
rs.getLong("id"),
rs.getString("nombre"),
rs.getInt("edad")
))
.list();
}
// 或者使用自动映射更简单
public List<Persona> findAll() {
return jdbcClient.sql("SELECT * FROM persona")
.query(Persona.class)
.list();
}带参数的查询:
public Optional<Persona> findById(Long id) {
return jdbcClient.sql("SELECT * FROM persona WHERE id = :id")
.param("id", id)
.query(Persona.class)
.optional();
}写操作:
public int actualizarEdad(Long id, int nuevaEdad) {
return jdbcClient.sql("UPDATE persona SET edad = :edad WHERE id = :id")
.param("edad", nuevaEdad)
.param("id", id)
.update();
}更简洁,充分利用 lambda 和方法引用,和 Optional 集成得好,对 AOT 和 GraalVM 的支持也更好。
测试改进
新的测试切片 @HttpServiceClientTest 只加载 HTTP 客户端需要的配置,不用起整个应用上下文:
@HttpServiceClientTest
class ProductoClientTest {
@Autowired
private ProductoClient productoClient;
@Test
void deberiaObtenerProducto() {
// 只加载 HTTP 客户端所需的配置
Producto producto = productoClient.obtenerProducto("123");
assertThat(producto).isNotNull();
}
}TestRestTemplate 也改进了,和 RestClient 集成更好,支持类型化响应:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class IntegrationTest {
@Autowired
private TestRestClient restClient;
@Test
void deberiaCrearUsuario() {
Usuario nuevoUsuario = new Usuario("Juan", "Pérez");
Usuario creado = restClient.post()
.uri("/api/usuarios")
.body(nuevoUsuario)
.exchange()
.expectStatus().isCreated()
.expectBody(Usuario.class)
.returnResult();
assertThat(creado.getId()).isNotNull();
}
}从 Spring Boot 3 迁移
几个必须处理的点:Jackson 从 2.x 升到 3.x,javax.* 完整迁移到 jakarta.*,Java 17 最低要求(建议 21+),Kotlin 需要 2.2+。RestTemplate 要换成 RestClient 或声明式客户端,Spring Security 里 lambda 配置变成强制的,一些配置属性改了名字。
Spring 官方推荐用 OpenRewrite 自动化大部分迁移:
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.42.0</version>
<configuration>
<activeRecipes>
<recipe>org.openrewrite.java.spring.boot4.UpgradeSpringBoot_4_0</recipe>
</activeRecipes>
</configuration>
</plugin>这个插件可以自动处理依赖更新、javax 到 jakarta 的命名空间变更、已弃用 API 的迁移和配置文件更新。
结论
Spring Boot 4 和 Spring Framework 7 做的事情可以总结为:让 Java 应用更轻、更可预测、更快、更安全。
模块化和 AOT 改善了启动时间和内存消耗。JSpecify 在开发时就拦住 NPE。声明式 API 砍掉样板代码。弹性模式内置进框架。可观测性一流。GraalVM 原生镜像为容器和云环境做了优化。
迁移不是没有成本的,要更新依赖、调整配置。但投入产出比很值。如果你在为未来几年的项目选平台,Spring Boot 4 是现在 Java 生态里最扎实的基础。