---
url: /diary/spring/springboot4-other-changes/index.md
description: >-
  Spring Boot 4 的其他核心变更，包括虚拟线程、GraalVM 原生镜像、可观测性、声明式 HTTP 客户端、弹性能力、API
  版本控制、测试变更等。
---
## 虚拟线程

Spring Boot 4 对 Java 21+ 虚拟线程（Virtual Threads）提供了**一等公民支持**。

### 启用方式

```yaml
spring:
  threads:
    virtual:
      enabled: true
```

### 效果

启用后以下场景自动使用虚拟线程：

* HTTP 请求处理（Tomcat/Jetty 的每个请求分配一个虚拟线程）
* `@Async` 异步方法
* 数据访问阻塞操作
* Spring WebClient 阻塞调用

### 监控

Actuator 新增 `/actuator/virtual-threads` 端点用于监控虚拟线程状态。

### 性能实测

IO 密集场景（大量数据库查询、HTTP 调用）吞吐量提升 **5-7 倍**，且无需修改任何业务代码。

### 与 Spring Boot 3.x 的差异

| 对比项 | Spring Boot 3.x | Spring Boot 4.x |
|---|---|---|
| 虚拟线程支持 | 实验性（需 Java 21+） | **一等公民**（推荐 Java 21+） |
| Actuator 监控 | 无专用端点 | **新增 `/actuator/virtual-threads`** |
| 自动调度范围 | 部分 | **全面覆盖请求、异步、数据访问** |

## GraalVM 原生镜像

从实验特性升级为**生产级支持**。

### 变化

| 对比项 | Spring Boot 3.x | Spring Boot 4.x |
|---|---|---|
| GraalVM 版本 | 22.x+ | **GraalVM 25+** |
| 支持级别 | 实验性 | **生产级** |
| AOT 编译速度 | 基准 | **提升 30%** |
| 内存占用 | 基准 | **减少 80%** |
| 反射控制 | 需手动配置 JSON | **新增 `@NativeHint` 注解** |

### @NativeHint 注解

精确控制反射和资源加载，替代手写 `reflect-config.json`：

```java
@NativeHint(
    types = @TypeHint(
        types = MyService.class,
        access = { AccessBits.DECLARED_CONSTRUCTORS, AccessBits.DECLARED_METHODS }
    ),
    resources = @ResourceHint(
        patterns = { "my-config.properties", "schema.sql" }
    )
)
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}
```

## 可观测性（Observability）

### Micrometer 2.0

Spring Boot 4 升级到 **Micrometer 2.0**，主要变化：

* API 更简洁，减少了样板代码
* 更好的 OpenTelemetry 集成
* Trace、Log、Metrics 三者无缝配合

### OpenTelemetry Starter

新增专门的 OpenTelemetry starter：

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

### SSL 证书过期监控

Actuator 增强了 SSL 证书过期监控能力，可提前预警证书即将过期：

```yaml
management:
  server:
    ssl:
      # 证书即将过期的告警天数
      certificate-notifier:
        warning-threshold: 30d
```

## 声明式 HTTP 客户端

Spring Framework 7 引入了声明式 HTTP 客户端，可作为 **Feign 的原生替代**。

### 基本使用

```java
// 声明接口
@HttpServiceClient("user-service")
public interface UserServiceClient {

    @GetExchange("/users/{id}")
    UserDTO getUserById(@PathVariable Long id);

    @PostExchange("/users")
    UserDTO createUser(@RequestBody UserCreateDTO dto);

    @GetExchange("/users")
    List<UserDTO> listUsers(@RequestParam String keyword);
}
```

### 优势

* **原生支持**，无需引入外部依赖
* 原生支持**响应式编程**（Reactive）
* 原生支持**虚拟线程**
* 与 Spring Cloud 服务发现无缝集成

### RestTemplate 弃用

`RestTemplate` 进入弃用倒计时，建议迁移到：

1. **`RestClient`**（同步，推荐简单场景）
2. **声明式 HTTP 客户端**（推荐复杂场景）

```java
// RestClient 示例（Spring Boot 3.x 已引入，4.x 继续推荐）
@RestController
public class MyController {

    private final RestClient restClient;

    public MyController(RestClient.Builder builder) {
        this.restClient = builder
            .baseUrl("https://api.example.com")
            .build();
    }

    public User getUser(Long id) {
        return restClient.get()
            .uri("/users/{id}", id)
            .retrieve()
            .body(User.class);
    }
}
```

## 弹性能力内置

Spring Framework 7 内置了重试、限流等弹性注解，**不再需要外部库**（如 Spring Retry、Resilience4j）。

### 使用方式

```java
@Configuration
@EnableResilientMethods  // 启用弹性方法支持
public class ResilientConfig {
}

@Service
public class MyService {

    @GetExchange("/data")
    @Retryable(maxAttempts = 3, delay = 100, multiplier = 2, maxDelay = 1000)
    @ConcurrencyLimit(3)  // 并发限制
    public String getData() {
        // 远程调用
    }
}
```

> `Spring Retry` 的依赖管理在 Spring Boot 4 中已被移除，因为弹性能力已内置到 Spring Framework 7。

## API 版本控制

Spring Framework 7 原生支持 API 版本控制。

### 基于注解的版本控制

```java
@RestController
@RequestMapping("/api/user")
public class UserController {

    @GetMapping(version = "1")
    public UserV1 getUserV1() {
        return new UserV1("张三");
    }

    @GetMapping(version = "2")
    public UserV2 getUserV2() {
        return new UserV2("张三", "zhangsan@example.com");
    }
}
```

### 四种版本传递方式

1. **路径映射**：`/api/v1/user`、`/api/v2/user`
2. **查询参数**：`/api/user?version=1`
3. **请求头**：`Accept-Version: 1`
4. **媒体类型头**：`Accept: application/vnd.company.v1+json`

通过配置选择版本传递策略：

```yaml
spring:
  mvc:
    versioning:
      default-version: 1
      type: header  # 可选：uri, header, media-type, param
      header: X-API-Version
```

## JSpecify 空安全

Spring Boot 4 全面采用 **JSpecify** 注解替代之前混乱的空值注解生态。

### 影响

* Spring API 中的 `@Nullable` 注解统一迁移到 JSpecify 规范
* **Kotlin 用户受益最大**：Spring API 在 Kotlin 中会自动呈现为空安全类型，编译器能精确推断可空性
* Java 用户可通过 JSpecify 注解获得更好的 IDE 空值提示

## 测试变更

### `@SpringBootTest` 行为变更

这是 Spring Boot 4 测试领域最大的变化：

```java
// Spring Boot 3.x：@SpringBootTest 自动提供 MockMvc 和 TestRestTemplate
@SpringBootTest
class MyTest {
    @Autowired
    MockMvc mockMvc;  // ✅ 自动注入

    @Autowired
    TestRestTemplate restTemplate;  // ✅ 自动注入
}

// Spring Boot 4.x：需要显式启用
@SpringBootTest
@AutoConfigureMockMvc  // 必须显式声明
@AutoConfigureTestRestTemplate  // 必须显式声明（如果需要）
class MyTest {
    @Autowired
    MockMvc mockMvc;  // ✅

    @Autowired
    TestRestTemplate restTemplate;  // ✅
}
```

### 新增 RestTestClient

推荐使用 `RestTestClient` 测试 REST 接口：

```java
@SpringBootTest
@AutoConfigureRestTestClient
class UserApiTest {

    @Autowired
    RestTestClient restTestClient;

    @Test
    void getUser() {
        restTestClient.get().uri("/api/user/1")
            .exchange()
            .expectStatus().isOk()
            .expectBody(UserDTO.class)
            .isEqualTo(new UserDTO(1L, "张三"));
    }
}
```

### MockBean 变更

```java
// Spring Boot 3.x
@MockBean
private UserService userService;

// Spring Boot 4.x
@MockitoBean  // 新名称
private UserService userService;

@MockitoSpyBean  // 替代 @SpyBean
private UserService userService;
```

### Test Starter

每个技术 starter 都有对应的 `-test` 版本，且已传递依赖 `spring-boot-starter-test`：

```xml
<!-- 不再需要显式声明 spring-boot-starter-test -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-test</artifactId>
    <scope>test</scope>
</dependency>
```

## 重要移除项一览

| 移除项 | 替代方案 | 说明 |
|---|---|---|
| **Undertow** | Tomcat / Jetty | 不支持 Servlet 6.1 |
| **Pulsar Reactive** | - | Spring Pulsar 移除了 reactor 支持 |
| **嵌入式 Uber Jar 启动脚本** | - | 不再支持 fully executable jar |
| **Spock 集成** | JUnit 5 | Spock 不支持 Groovy 5 |
| **Spring Session Hazelcast/MongoDB** | - | 交给各自团队维护 |
| **`@MockBean` / `@SpyBean`** | `@MockitoBean` / `@MockitoSpyBean` | - |
| **`MockitoTestExecutionListener`** | `MockitoExtension` | - |
| **`HttpMessageConverters`** | `ClientHttpMessageConvertersCustomizer` / `ServerHttpMessageConvertersCustomizer` | - |
| **Spring Retry 依赖管理** | 内置 `@Retryable` | 弹性能力已内置到 Spring Framework 7 |
| **Spring Batch 默认数据库存储** | `spring-boot-starter-batch-jdbc` | 需显式引入 |

### 其他行为变更

| 变更 | 说明 |
|---|---|
| **`RestTemplate` 进入弃用倒计时** | 建议迁移到 `RestClient` 或声明式 HTTP 客户端 |
| **DevTools Live Reload 默认禁用** | 需手动 `spring.devtools.livereload.enabled=true` |
| **Liveness/Readiness 探针默认启用** | 可通过 `management.endpoint.health.probes.enabled` 关闭 |
| **`spring-boot-starter-web` 重命名** | 改为 `spring-boot-starter-webmvc`（旧名保留为 deprecated） |
| **`spring-boot-starter-aop` 重命名** | 改为 `spring-boot-starter-aspectj` |
| **包路径重组** | `BootstrapRegistry` 移至 `org.springframework.boot.bootstrap` 等 |

## Kotlin 支持增强

* Kotlin 基线升级到 **2.2**
* 新增 `spring-boot-starter-kotlinx-serialization-json`
* 协程自动上下文传播
* `BeanRegistrarDsl` 支持 DSL 风格注册 Bean

```kotlin
// Kotlin DSL Bean 注册（Spring Boot 4 新特性）
beans {
    bean<MyService>()
    bean<AnotherService>()
    bean {
        MyController(ref(), ref())
    }
}
```

***

> 相关文章：
>
> * [Spring Boot 4 概览与迁移指南](./01.SpringBoot4概览与迁移指南.md)
> * [Jackson 配置与迁移](./02.Jackson配置与迁移.md)
> * [Redis 集成使用](./03.Redis集成使用.md)
> * [MyBatis-Flex 实战](./04.MyBatis-Flex实战.md)
