0
点赞
收藏
分享

微信扫一扫

Feign两种用法的优劣对比分析

快乐与微笑的淘气 2022-03-25 阅读 75

带着问题出发:在微服务中,为了让服务生产者(producer)与服务消费者(consumer)优雅通讯,Feign接口该如何定义?

Feign是什么?

在微服务中,Feign是一个​伪RPC​组件,它底层对httpClient/okhttp等HTTP通讯框架做了一层代理(屏蔽了底层细节,也不需要关心通讯配置),​基于接口注解​的方式完成HTTP客户端请求封装。

Feign做了什么?

  1. 参数解析和装载
  2. 针对制定的FeignClient,生成动态代理
  3. 针对FeignClient中的方法描述进行解析
  4. 组装出一个Request对象,发起请求

Feign的两种用法

比如,订单服务要调用用户服务:

用法一:服务生产者定义Feign

  • 接口定义在api模块,添加注解@FeignClient:​user-api /xxx/user/feign/IUserFeignClient.java
  • 实现类在service模块,添加注解@RestController:​user-service /xxx/user/feign/UserFeignClient.java
  • 把api模块打成jar包,deploy到maven仓库
  • consumer通过maven依赖该jar包
  • 注入bean类:​IUserFeignClient​,调用接口方法​userFeignClient.login();

用法二:服务消费者定义Feign

  • 接口定义在consumer的service模块,添加注解@FeignClient:​order-service /xxx/user/service/UserService.java
  • API实现在producer的service模块controller包下:​user-service /xxx/user/controller/UserController.java​,注意没有在代码层面实现consumer的UserService接口
  • 注入bean类:​UserService​,调用接口方法​userService.login();

两种用法的优劣对比

基本上两者​优缺点互补​,那就说说它们各自的​特性​吧。

服务生产者定义Feign(面向SPI)

「强约束」​面向SPI是强约束的,consumer引入Jar包,在代码层面对接口进行实现。版本一致的情况下可以在编码阶段发现问题进行修改。比如producer修改了Feign接口入参数量,consumer引入最新版本jar包能立马检查出来。​SPI是语言相关​的,因为jar包只能在java项目引入。

「避免重复定义」​producer定义好Feign接口后,consumer引入jar包后就知道怎么使用,无须在多个consumer重复定义入参出参。

服务消费者定义Feign(面向API)

「弱约束」​面向API是弱约束的,producer和consumer之间通过开发人员的约定来约束。上面提到,FeignClient默认代理HttpClient做为底层实现,HttpClient就是面向API编程的。两者区别在于HttpClient需要写​大量实现代码​,而FeignClient只​定义接口​。而没有了jar包依赖,consumer就不一定是java项目了,因为​API是语言无关​的。

「简化开发流程」​面向SPI开发模式需要在producer定义feign,然后打成jar,deploy到maven仓库,再引入到consumer工程。。。后续迭代需求得​频繁修改依赖包版本​,整条链路非常长。而面向API开发模式简单直接,让开发人员聚焦业务代码,这也是弱约束带来的便利。

「裁剪灵活」​假设producer暴露100个接口,consumer只需要调用其中20个,这种情况下对接口裁剪就非常灵活了。不仅能对​接口​裁剪,还能对​接口参数​、​返回值​进行裁剪,只保留当前业务需要的入参出参,​隔离性​非常好。

「影响范围小」​producer作为下层系统,只需要把当前系统的功能实现即可,不用受到上层系统约束。如果要配合consumer提供Feign接口,需要改造producer,把原​service层的VO迁到api层变成DTO​。我们都知道,​DTO不该使用充血模型​,但VO没有这个约束,迁层就要考虑把VO依赖的类都一起迁,对于producer就会有大量的​代码改造​。开发一个需求还需要改动大量下层系统的代码,无疑增加了许多风险。

使用场景

从约束性、隔离性、灵活性、影响范围等整体考虑,个人更推荐使用第二种方式,也就是​服务消费者定义Feign接口​,而且​定义在service层的service包下​即可,无须跟普通的Service类区别对待。当然,文中只列举了部分特性,实际生产还要结合大家各自项目的特点来选择。

心得体会

学会从不同的角度去思考问题本身,不要让过往的经验成为通向远方的绊脚石。

「关注我,一起学习探讨生产落地方案~」

举报

相关推荐

0 条评论