返回首页

HttpClient Spring 7:Feign 替代品

Spring 7 引入声明式 HttpClient,作为 FeignClient 的原生替代品。对 OpenAPI 生成器、虚拟线程和 Kotlin 空安全的支持简化了外部 API 的集成。设置、验证和错误处理的详细信息。

Spring 7 HttpClient:替换 Feign 的完整指南
Advertisement 728x90

Spring 7 声明式 HttpClient:FeignClient 的最佳替代

Spring 7 引入了原生的声明式 HttpClient,基于 RestClient 和 WebClient 构建。它使用熟悉的注解如 @GetExchange 和 @PostExchange,与控制器中的 @GetMapping 类似。通过接口定义出站 HTTP 请求,无需手动实现。

关键接口示例如下:

public interface UserClient {

    @GetExchange("/api/users/{id}")
    UserResponse getUser(
        @PathVariable("id") Long id,
        @RequestParam(name = "includeDetails", defaultValue = "false") boolean includeDetails,
        @RequestHeader("Authorization") String authToken,
        @RequestHeader("X-Request-Id") String requestId
    );

    @PostExchange("/api/users")
    UserResponse createUser(
        @RequestBody @Valid CreateUserRequest request,
        @RequestHeader("Authorization") String authToken
    );

    @PatchExchange("/api/users/{id}")
    void updateUserEmail(
        @PathVariable("id") Long id,
        @RequestParam("email") String email,
        @RequestHeader("Authorization") String authToken
    );
}

HttpClient 开箱即用支持可观测性,且无需 Spring Cloud——不同于 FeignClient,后者自 2022 年起进入维护模式。

Google AdInline article slot

与 OpenAPI Generator 集成

要自动化生成客户端,使用 openapi-generator 结合 spring-http-interface 库。

Maven 插件配置:

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>${openapi-generator.version}</version>
    <executions>
       <execution>
    <id>generate-weather-client</id>
    <goals>
       <goal>generate</goal>
    </goals>
    <configuration>
       <inputSpec>${project.basedir}/src/main/resources/openapi/external/weather-api.yaml</inputSpec>
       <generatorName>spring</generatorName>
       <library>spring-http-interface</library>
       <output>${project.build.directory}/generated-sources/openapi-client</output>
       <apiPackage>ulllie.exchange.openapi.gen.client.api</apiPackage>
       <modelPackage>ulllie.exchange.openapi.gen.client.model</modelPackage>
       <generateApis>true</generateApis>
       <generateModels>true</generateModels>
       <generateSupportingFiles>false</generateSupportingFiles>
       <configOptions>
          <useSpringBoot4>true</useSpringBoot4>
          <useJackson3>true</useJackson3>
          <interfaceOnly>true</interfaceOnly>
          <skipDefaultInterface>true</skipDefaultInterface>
          <useBeanValidation>true</useBeanValidation>
          <annotationLibrary>none</annotationLibrary>
          <serializationLibrary>jackson</serializationLibrary>
          <useTags>true</useTags>
       </configOptions>
    </configuration>
</execution>
    </executions>
</plugin>

这会生成类似这样的接口:

Google AdInline article slot
public interface OpenMeteoApi { 
  @HttpExchange(method = "GET", value = "/v1/forecast")   
  ResponseEntity<ForecastResponse> getForecast( 
    @RequestParam("latitude") Double latitude, 
    @RequestParam("longitude") Double longitude 
  );
}

服务连接与配置

通过 import 配置:

@Configuration  @ImportHttpServices(group = "weather", types = OpenMeteoApi.class)  
public class WeatherRestClientConfig implements RestClientHttpServiceGroupConfigurer {    
  @Override      
  public void configureGroups(Groups<RestClient.Builder> groups) { 
    groups.filterByName("weather").forEachClient(
      ($, builder) -> builder.baseUrl("https://api.weather.com") 
    );    
  }  
}

错误处理通过 defaultStatusHandler 配置:

builder.baseUrl(properties.baseUrl())
  .defaultStatusHandler(
  status -> status.is4xxClientError() || status.is5xxServerError(),               
  errorHandler         
);

自定义 HttpErrorHandler 可针对 4xx/5xx 状态码定制逻辑,支持 Resilience4j 集成,或使用 @ControllerAdvice。

Google AdInline article slot

核心特性:

  • 拦截器配置
  • Resilience4j 集成
  • ResponseSpec 级错误处理

RestClient 与 WebClient 在 Project Loom 下的对比

启用虚拟线程(spring.threads.virtual.enabled=true)后,阻塞式 RestClient 提供 I/O 可扩展性,无需响应式编程。

优势:

  • 易调试的命令式代码
  • 无响应式管道
  • I/O 密集任务性能媲美 WebClient

响应式场景下,选择 WebClient.Builder 生成 Mono/Flux 签名。

验证挑战与解决方案

Bean Validation 不会递归嵌套对象,因为生成器跳过 @Valid。

解决方案:

  • OpenAPI 中的 x-field-extra-annotation@jakarta.validation.Valid ——需修改规范。
  • AlwaysTraversableResolver ——全局遍历整个对象树,但易引发循环和性能问题。
  • 自定义 Mustache 模板 ——生成时自动添加 @Valid。

额外提示:生成 Kotlin 数据类以确保空安全。

data class ForecastResponse(
  val temperature: Double,
  val windSpeed: Double?
)

依赖:kotlin-stdlib + jackson-module-kotlin。空值违规时快速失败反序列化。

核心要点

  • HttpClient 是 Spring Framework 原生功能,无需 Spring Cloud 依赖。
  • OpenAPI generator 结合 spring-http-interface 生成即用接口。
  • 虚拟线程简化 I/O 处理,无需响应式。
  • Kotlin 数据类及早捕获空值问题。
  • 错误处理和验证完全可定制。

— Editorial Team

Advertisement 728x90

继续阅读