Spring Boot HttpExchange 入门


这是Spring 6.x 声明式 HTTP 客户端缺失的start:

  • 消除模板代码、
  • 生成服务器基础实现代码、
  • 支持 RequestMapping 注释、
  • 支持负载平衡器、
  • 支持本地图片、
  • 动态刷新、
  • 动态请求超时等!

背景上下文
Spring 6 通过 @HttpExchange 注解引入了对声明式 HTTP 客户端的本地支持。对 SpringCloud OpenFeign 的依赖可以被有效取代。

@HttpExchange("https://my-json-server.typicode.com")
interface PostApi {
    @GetExchange(
"/typicode/demo/posts/{id}")
    Post getPost(@PathVariable(
"id") int id);
}

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @Bean
    PostApi postApi(RestClient.Builder builder) {
        HttpServiceProxyFactory factory = HttpServiceProxyFactory
                .builderFor(RestClientAdapter.create(builder.build()))
                .build();
        return factory.createClient(PostApi.class);
    }

   
// Imagine there are 100 HttpExchange clients 

    @Bean
    ApplicationRunner runner(PostApi api) {
        return args -> api.getPost(1);
    }
}

但是还有啥问题?

  • 没有自动配置:客户端无法进行自动配置;必须通过客户端 bean 手动实例化客户端。在处理大量客户端时,这一过程会变得特别繁琐。
    对于习惯于使用 Spring Cloud OpenFeign 的用户来说,@EnableFeignClients 注解具有极大的优势,可显著减少重复代码的数量。
  • 不支持 Spring Web 注释:虽然对声明式 HTTP 客户端的本机支持是一个值得欢迎的功能,但它引入了一套新的注解,如 @GetExchange、@PostExchange 等。
    遗憾的是,HttpServiceProxyFactory 并不支持 @GetMapping 和 @PostMapping 等 Spring Web 注释。这种不支持会严重阻碍习惯使用 Spring Cloud OpenFeign 并考虑过渡到 Spring 6.x 的用户,使迁移过程变得极具挑战性。

这个项目解决了上述问题, 主要目标是

  • 推广使用 @HttpExchange 作为定义 API 接口的中性注解。
  • 为 Spring 6 声明式 HTTP 客户端提供类似 Spring Cloud OpenFeign 的体验。
  • 支持 Spring Web 注释(@RequestMapping、@GetMapping)。
  • 不引入外部注解,易于迁移到其他实现。

加入依赖:

<dependency>
    <groupId>io.github.danielliu1123</groupId>
    <artifactId>httpexchange-spring-boot-starter</artifactId>
    <version>3.2.5</version>
</dependency>

主代码:

@HttpExchange("https://my-json-server.typicode.com")
interface PostApi {
    @GetExchange(
"/typicode/demo/posts/{id}")
    Post getPost(@PathVariable(
"id") int id);
}

@SpringBootApplication
@EnableExchangeClients
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @Bean
    ApplicationRunner runner(PostApi api) {
        return args -> api.getPost(1);
    }
}