Spring 6 正式“抛弃” feign

来源:juejin.cn/post/7173271507047546893

  • 完成一个 Demo
  • GetExchange(HttpExchange)注解
  • UserApiService 实例的创建
  • 其他特性
  • 为什么需要 Spring Reactive Web 的依赖
  • 总结

近期,Spring 6 的第一个 GA 版本发布了,其中带来了一个新的特性——HTTP Interface。这个新特性,可以让开发者将 HTTP 服务,定义成一个包含特定注解标记的方法的 Java 接口,然后通过对接口方法的调用,完成 HTTP 请求。看起来很像使用 Feign 来完成远程服务调用,这可能是 Spring “抛弃” feign 等 http 调用的一种趋势,Spring 要规范和简化这一块的实现了,让开发者更关注聚集于业务。下面我们参考官方文档来完成一个 Demo。

完成一个 Demo

首先创建一个简单的 HTTP 服务,这一步可以创建一个简单的 Spring Boot 工程来完成。

先创建一个实体类:

public class User implements Serializable {

    private int id;
    private String name;
    // 省略构造方法、Getter和Setter
    @Override
    public String toString() {
        return id + ":" + name;
    }
}

再写一个简单的 Controller:

@GetMapping("/users")
public List<User> list() {
    return IntStream.rangeClosed(1, 10)
            .mapToObj(i -> new User(i, "User" + i))
            .collect(Collectors.toList());
}

确保启动服务之后,能够从http://localhost:8080/users地址获取到一个包含十个用户信息的用户列表。

下面我们新建一个 Spring Boot 工程。

Spring initializr

这里需要注意,Spring Boot 的版本至少需要是 3.0.0,这样它以来的 Spring Framework 版本才是 6.0 的版本,才能够包含 HTTP Interface 特性,另外,Spring Framework 6.0 和 Spring Boot 3.0 开始支持的 Java 版本最低是 17,因此,需要选择至少是 17 的 Java 版本。

另外,需要依赖 Spring Web 和 Spring Reactive Web 依赖,原因下文中会提到。

创建好新的 Spring Boot 工程后,首先需要定义一个 HTTP Interface 接口。最简单的定义如下即可:

public interface UserApiService {
    @GetExchange("/users")
    List<User> getUsers();
}

然后,我们可以写一个测试方法。

@Test
void getUsers() {
   WebClient client = WebClient.builder().baseUrl("http://localhost:8080/").build();
   HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build();
   UserApiService service = factory.createClient(UserApiService.class);
   List<User> users = service.getUsers();
   for (User user : users) {
      System.out.println(user);
   }
}

最终回打印获取到的是个用户信息:

1:User1
2:User2
...
9:User9
10:User10

以上是一个最简单的示例,下面我们看看其中的一些细节。

GetExchange(HttpExchange)注解

上文例子中的 GetExchange 注解代表这个方法代替执行一个 HTTP Get 请求,与此对应,Spring 还包含了其他类似的注解:

GetExchange

这些注解定义在spring-web模块的org.springframework.web.service.annotation包下,除了 HttpExchange 之外,其他的几个都是 HttpExchange 的特殊形式,这一点与 Spring MVC 中的 RequestMapping/GetMapping 等注解非常相似。

以下是 HttpExchange 的源码:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
@Reflective(HttpExchangeReflectiveProcessor.class)
public @interface HttpExchange {

    @AliasFor("url")
    String value() default "";

    @AliasFor("value")
    String url() default "";

    String method() default "";

    String contentType() default "";

    String[] accept() default {};

}

在上面的例子中,我们只指定了请求的资源路径。

UserApiService 实例的创建

在上面例子中,我们定义的 HTTP Interface 接口是 UserApiService,在测试方法中,我们通过 HttpServiceProxyFactory 创建了 UserApiService 的实例,这是参考了 Spring 的官方文档的写法。

你也可以将创建的过程写到一个 @Bean 方法中,从而可以将创建好的实例注入到其他的组件中。

我们再定义 UserApiService 的时候,只是声明了一个接口,那具体的请求操作是怎么发出的呢,我们可以通过 DEBUG 模式看得出来,这里创建的 UserApiService 的实例,是一个代理对象:

代理对象

目前,Spring 还没有提供更方便的方式来创建这些代理对象,不过,之后的版本肯定会提供,如果你感兴趣的话,可以从 HttpServiceProxyFactory 的createClient方法的源码中看到一些与创建 AOP 代理相似的代码,因此,我推测 Spring 之后可能会增加类似的注解来方便地创建代理对象。

其他特性

除了上述例子中的简单使用之外,添加了 HttpExchange 的方法还支持各种类型的参数,这一点也与 Spring MVC 的 Controller 方法类似,方法的返回值也可以是任意自定义的实体类型(就像上面的例子一样),此外,还支持自定义的异常处理。

为什么需要 Spring Reactive Web 的依赖

上文中创建工程的时候,引入了 Spring Reactive Web 的依赖,在创建代理的service对象的时候,使用了其中的 WebClient 类型。这是因为,HTTP Interface 目前只内置了 WebClient 的实现,它属于 Reactive Web 的范畴。Spring 在会在后续版本中推出基于 RestTemplate 的实现。

总结

本文带你对 HTTP Interface 特性进行了简单的了解,我之后会深入研究这个特性,也会追踪后续版本中的改进并与你分享,欢迎点赞加关注。

程序汪资料链接

程序汪接私活项目目录,2023年总结

Java项目分享  最新整理全集,找项目不累啦 07版

欢迎添加程序汪微信 itwang007  进粉丝群

相关推荐

  • 10个能用AI来提升收入的方法
  • 董宇辉与戴建业教授同游东湖,“你小子”火了!
  • 工作中最常见的 6 种 OOM 问题
  • 分库分表实战
  • Spring Boot集成zxing实现生成二维码功能
  • Java日志系统历史从入门到崩溃
  • 几种常见的 Kafka 集群监控工具
  • 持续移动开发如何从测试自动化中获益
  • 大模型企业怎么“卷”过 | 直播预告
  • 把大模型装进手机,小米、OPPO、vivo 卷起来了!
  • Stable Diffusion核心团队全部离职!Kimi大面积宕机,月之暗面已扩容5次;Redis不再“开源”引争议 |Q资讯
  • 能玩3D游戏的AI玩家!谷歌新智能体SIMA发布,但水平还在“新手村”
  • 微软围着Copilot 转!首款AI PC能算惊艳吗?网友:9分钟宣传片让人昏昏欲睡
  • Redis“叛逃”开源,得罪了几乎所有人
  • 搭建一个符合大厂标准的Vue3+Ts +Vite脚手架
  • JS官方宣布:通过了groupBy方法的提案!开发效率又提升了~
  • AI的大机会
  • Redis 不再开源??
  • JDK 22 发布正式版了
  • 华为某外包:名校毕业,自以为能力吊打华为16级以上员工,年薪总包却只有30万。网友:刚接触职场?自我感觉太良好了?