最佳实践就是人们在开发过程中总结出来的不错的用法,是一种比较好的使用方式。
我们可以发现,Feign的客户端与服务提供者的controller代码非常相似:
Feign客户端:
服务提供者的controller代码:
既然如此,那我们肯定是希望把重复的代码给省去
1.方式一:继承
给消费者的FeignClient和提供者的controller定义统一的父接口作为标准。
不过这种方式Spring并不推荐
这是因为:
- 服务紧耦合(两个不同的服务(服务提供者和消费者)却要继承或实现同一个api接口)
- 父接口参数列表中的映射不会被继承(参数列表中的注解映射并不会继承 ,因此Controller中必须再次声明方法、参数列表、注解 )
2.方式二:抽取
将Feign的Client抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用。例如,将UserClient、User、Feign的默认配置都抽取到一个feign-api包中,所有微服务引用该依赖包,即可直接使用。
不过这种方式也存在一些问题,如一个消费者只想使用一个接口,但是却要把所有的接口都引入。在实际开发中,具体选用哪种方式要具体问题具体分析,没有一概而论的方法。
3.实现基于抽取的最佳实践
Ⅰ.抽取
创建一个module,命名为feign-api,将消费者的Feign客户端、pojo、Feign配置等都抽取到feign-api中
引入feign的starter依赖
<dependencies>
<!-- feign的客户端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
Ⅱ.在消费者中引入feign-api
将消费者的Feign客户端、pojo、Feign配置都删掉,再引入
<!-- 基于Feign的抽取的最佳实践方式-->
<dependency>
<groupId>cn.itcast.demo</groupId>
<artifactId>feign-api</artifactId>
<version>1.0</version>
</dependency>
Ⅲ.扫描包问题
如果这时候就启动的话,会出现扫描包问题:
这是因为消费者只能默认只能扫描到自己的包,而Feign的客户端@FeignClient现在在feign-api下,所以是扫描不到的(本例中UserClient现在在cn.itcast.feign.clients包下,而order-service的@EnableFeignClients注解是在cn.itcast.order包下,不在同一个包,无法扫描到UserClient)
解决办法1:指定Feign应该扫描的包:
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
解决办法2:指定需要加载的Client接口:
@EnableFeignClients(clients = {UserClient.class}) // 开启Feign的功能,指定需要加载的Client接口
推荐方法2,因为这样可以做到用什么取什么,避免浪费