Skip to content

Latest commit

 

History

History
586 lines (445 loc) · 13.6 KB

File metadata and controls

586 lines (445 loc) · 13.6 KB

Spring Boot 4.0 学习指南

📅 发布日期:2025年11月20日
🎯 适合人群:有 Spring Boot 3.x 基础的开发者


📋 目录

  1. 环境准备
  2. 快速开始
  3. 新特性详解
  4. 实战练习
  5. 升级指南
  6. 常见问题

1. 环境准备

1.1 必需环境

工具 最低版本 推荐版本 说明
Java 17 21 推荐21以使用虚拟线程
Maven 3.6 3.9+ 或使用 Gradle 9
IDE - IntelliJ IDEA 2024+ 需要支持 Java 21

1.2 验证环境

# 检查 Java 版本
java -version
# 应显示: openjdk version "21.x.x" 或更高

# 检查 Maven 版本
mvn -version
# 应显示: Apache Maven 3.9.x 或更高

1.3 创建项目

方式一:使用 Spring Initializr

  1. 访问 https://start.spring.io
  2. 选择 Spring Boot 4.0.0
  3. 选择 Java 21
  4. 添加依赖:Web, Actuator

方式二:使用本演示项目

cd d:\code\hd-backend\spring-boot4-demo
mvn clean install

2. 快速开始

2.1 运行项目

# 方式一:Maven 运行
mvn spring-boot:run

# 方式二:打包后运行
mvn clean package
java -jar target/spring-boot4-demo.jar

2.2 访问接口

启动后访问 http://localhost:8090 查看所有演示接口:

# 查看首页(所有接口列表)
curl http://localhost:8090/

# 测试 API 版本控制
curl http://localhost:8090/api/v1/users
curl http://localhost:8090/api/v2/users

# 测试 HTTP Service Client
curl http://localhost:8090/github/users/spring-projects

# 测试可观测性
curl http://localhost:8090/observability/auto-trace

3. 新特性详解

3.1 HTTP Service Clients

是什么?

声明式 HTTP 客户端,类似于 OpenFeign,但是 Spring 原生支持,无需额外依赖。

为什么用?

  • ✅ 无需手动编写 RestTemplate/WebClient 调用代码
  • ✅ 接口定义清晰,易于维护
  • ✅ Spring 原生,与生态深度集成

怎么用?

第一步:定义接口

// 文件:feature1_http_service/GitHubService.java

@HttpExchange(url = "https://api.github.com")
public interface GitHubService {

    // GET 请求
    @GetExchange("/users/{username}")
    Map<String, Object> getUser(@PathVariable String username);

    // POST 请求
    @PostExchange("/repos")
    Map<String, Object> createRepo(@RequestBody Map<String, String> repo);
    
    // 带请求头
    @GetExchange("/user")
    Map<String, Object> getCurrentUser(@RequestHeader("Authorization") String token);
}

第二步:配置代理

// 文件:feature1_http_service/HttpServiceConfig.java

@Configuration
public class HttpServiceConfig {

    @Bean
    public GitHubService gitHubService() {
        RestClient restClient = RestClient.builder()
                .baseUrl("https://api.github.com")
                .defaultHeader("User-Agent", "My-App")
                .build();
        
        HttpServiceProxyFactory factory = HttpServiceProxyFactory
                .builderFor(RestClientAdapter.create(restClient))
                .build();
        
        return factory.createClient(GitHubService.class);
    }
}

第三步:注入使用

@RestController
@RequiredArgsConstructor
public class MyController {

    private final GitHubService gitHubService;

    @GetMapping("/user/{name}")
    public Map<String, Object> getUser(@PathVariable String name) {
        return gitHubService.getUser(name);  // 直接调用接口方法
    }
}

常用注解

注解 说明 示例
@HttpExchange 定义基础URL @HttpExchange(url = "https://api.example.com")
@GetExchange GET 请求 @GetExchange("/users")
@PostExchange POST 请求 @PostExchange("/users")
@PutExchange PUT 请求 @PutExchange("/users/{id}")
@DeleteExchange DELETE 请求 @DeleteExchange("/users/{id}")
@PatchExchange PATCH 请求 @PatchExchange("/users/{id}")

3.2 API Versioning

是什么?

内置的 API 版本控制支持,无需手动实现。

为什么用?

  • ✅ 标准化的版本控制方案
  • ✅ 支持多种版本传递方式
  • ✅ 配置简单,开箱即用

怎么用?

第一步:启用配置

# application.yml
spring:
  mvc:
    apiversion:
      enabled: true
      parameter-name: v           # 参数名:?v=1.0
      header-name: X-API-Version  # 请求头名
      default-version: 1.0        # 默认版本

第二步:编写多版本接口

// 文件:feature2_api_versioning/ApiVersioningController.java

@RestController
@RequestMapping("/api")
public class ApiVersioningController {

    // V1 版本 - 简单数据
    @GetMapping("/v1/users")
    public Map<String, Object> getUsersV1() {
        return Map.of(
            "version", "1.0",
            "users", List.of("张三", "李四")
        );
    }

    // V2 版本 - 详细数据
    @GetMapping("/v2/users")
    public Map<String, Object> getUsersV2() {
        return Map.of(
            "version", "2.0",
            "users", List.of(
                Map.of("id", 1, "name", "张三", "email", "zs@example.com"),
                Map.of("id", 2, "name", "李四", "email", "ls@example.com")
            )
        );
    }
}

第三步:客户端调用

# 方式1:URL路径
curl http://localhost:8090/api/v1/users
curl http://localhost:8090/api/v2/users

# 方式2:请求参数
curl "http://localhost:8090/api/users?v=1.0"
curl "http://localhost:8090/api/users?v=2.0"

# 方式3:请求头
curl -H "X-API-Version: 1.0" http://localhost:8090/api/users
curl -H "X-API-Version: 2.0" http://localhost:8090/api/users

3.3 OpenTelemetry Starter

是什么?

一站式可观测性支持,自动配置 Metrics(指标)和 Traces(追踪)。

为什么用?

  • ✅ 无需手动集成 OpenTelemetry SDK
  • ✅ 自动为 HTTP 请求创建 Span
  • ✅ 支持 OTLP 协议导出到 Jaeger、Zipkin 等

怎么用?

第一步:添加依赖

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

第二步:配置导出端点

# application.yml
management:
  tracing:
    sampling:
      probability: 1.0  # 采样率 100%
  otlp:
    tracing:
      endpoint: http://localhost:4318/v1/traces
    metrics:
      endpoint: http://localhost:4318/v1/metrics

第三步:自动追踪生效

所有 HTTP 请求自动创建 Span,无需额外代码!

第四步:手动创建 Observation(可选)

// 文件:feature3_opentelemetry/ObservabilityController.java

@RestController
@RequiredArgsConstructor
public class ObservabilityController {

    private final ObservationRegistry observationRegistry;

    @GetMapping("/my-operation")
    public String myOperation() {
        return Observation.createNotStarted("my.custom.operation", observationRegistry)
                .lowCardinalityKeyValue("type", "demo")
                .observe(() -> {
                    // 你的业务逻辑
                    return "操作完成";
                });
    }
}

3.4 Task Decoration

是什么?

支持多个 TaskDecorator,自动组合成 CompositeTaskDecorator

为什么用?

  • ✅ 关注点分离:日志、MDC、指标各自独立
  • ✅ 按 @Order 顺序执行
  • ✅ 易于扩展和维护

怎么用?

第一步:创建多个装饰器

// 装饰器1:日志记录(最先执行)
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class LoggingTaskDecorator implements TaskDecorator {
    @Override
    public Runnable decorate(Runnable runnable) {
        return () -> {
            log.info("任务开始");
            runnable.run();
            log.info("任务结束");
        };
    }
}

// 装饰器2:MDC上下文传递
@Component
@Order(0)
public class MdcTaskDecorator implements TaskDecorator {
    @Override
    public Runnable decorate(Runnable runnable) {
        Map<String, String> context = MDC.getCopyOfContextMap();
        return () -> {
            if (context != null) MDC.setContextMap(context);
            try {
                runnable.run();
            } finally {
                MDC.clear();
            }
        };
    }
}

// 装饰器3:指标收集(最后执行,最接近实际任务)
@Component
@Order(1)
public class MetricsTaskDecorator implements TaskDecorator {
    @Override
    public Runnable decorate(Runnable runnable) {
        return () -> {
            Timer.Sample sample = Timer.start();
            try {
                runnable.run();
            } finally {
                sample.stop(taskTimer);
            }
        };
    }
}

第二步:启用异步

@Configuration
@EnableAsync
public class AsyncConfig {
    // Spring Boot 4.0 自动组合所有 TaskDecorator
}

第三步:使用异步方法

@Service
public class MyService {
    
    @Async
    public CompletableFuture<String> asyncTask() {
        // 这个任务会被所有装饰器包装
        return CompletableFuture.completedFuture("完成");
    }
}

执行顺序:

LoggingTaskDecorator (Order=HIGHEST)
  └─> MdcTaskDecorator (Order=0)
        └─> MetricsTaskDecorator (Order=1)
              └─> 实际任务

3.5 RestTestClient

是什么?

新的测试客户端,提供流式 API,更简洁的测试代码。

为什么用?

  • ✅ 流式 API,代码更简洁
  • ✅ 更好的断言支持
  • ✅ 与 AssertJ 深度集成

怎么用?

// 文件:test/.../Feature5RestTestClientTest.java

@SpringBootTest
@AutoConfigureMockMvc
class MyTest {

    @Autowired
    private MockMvcTester mockMvc;  // 新的测试客户端

    @Test
    void testGetUsers() {
        mockMvc.get().uri("/api/v1/users")
                .assertThat()
                .hasStatusOk()                           // 断言状态码
                .bodyJson()
                .extractingPath("$.version")             // 提取 JSON 字段
                .isEqualTo("1.0");                       // 断言值
    }

    @Test
    void testPostUser() {
        mockMvc.post().uri("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"name\": \"张三\"}")
                .assertThat()
                .hasStatus(HttpStatus.CREATED)
                .bodyJson()
                .extractingPath("$.id")
                .isNotNull();
    }

    @Test
    void testWithHeader() {
        mockMvc.get().uri("/api/users")
                .header("X-API-Version", "2.0")
                .assertThat()
                .hasStatusOk();
    }
}

4. 实战练习

练习1:创建一个天气服务客户端

使用 HTTP Service Client 调用天气 API:

@HttpExchange(url = "https://api.weatherapi.com/v1")
public interface WeatherService {
    
    @GetExchange("/current.json")
    Map<String, Object> getCurrentWeather(
        @RequestParam("key") String apiKey,
        @RequestParam("q") String city
    );
}

练习2:实现版本化的用户API

创建 V1、V2、V3 三个版本的用户接口,逐步增加返回字段。

练习3:添加自定义 TaskDecorator

创建一个 SecurityContextTaskDecorator,在异步任务中传递安全上下文。


5. 升级指南

从 Spring Boot 3.x 升级到 4.0

第一步:升级到 3.5

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.5.0</version>
</parent>

第二步:升级 Java 版本

<properties>
    <java.version>21</java.version>
</properties>

第三步:升级到 4.0

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>4.0.0</version>
</parent>

第四步:检查废弃 API

参考官方迁移指南: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Migration-Guide


6. 常见问题

Q1: 为什么需要 Java 21?

Spring Boot 4.0 基于 Spring Framework 7.0,要求 Java 17+。推荐 Java 21 是因为:

  • 虚拟线程(Virtual Threads)正式发布
  • 更好的性能和内存管理

Q2: 可以继续使用 Feign 吗?

可以,但推荐使用原生的 HTTP Service Client:

  • 无需额外依赖
  • 与 Spring 生态更好集成
  • 支持响应式编程

Q3: OpenTelemetry 和 Micrometer 的关系?

Spring Boot 4.0 中:

  • Micrometer 是抽象层(Observation API)
  • OpenTelemetry 是具体实现
  • 两者深度集成,可以同时使用

Q4: 如何回退到 Spring Boot 3.x?

修改 pom.xml 中的 parent 版本即可:

<version>3.5.0</version>

📚 参考资源


💡 提示:遇到问题可以在 Stack Overflow 搜索 spring-boot 标签。

祝学习愉快! 🎉