前言
-
本次示例代码的文件结构如下图所示。
-
本文总结了 2 种 Feign 的最佳实践方案。
-
方式一 (继承) :给消费者的
FeignClient
和提供者的controller
定义统一的父接口作为标准。 -
方式二 (抽取) :将
FeignClient
抽取为独立模块,并且把接口有关的 POJO 、默认的 Feign 配置都放在这个模块中,提供给消费者使用。
方式一:继承
-
本例中,服务的消费者就是订单服务
order-service
。打开其clients/UserClient.java
。
方式二:抽取
-
以前,消费者远程调用提供者的接口时,都把
FeignClient
写在消费者的服务之中,如下图所示。 -
但是,这种写法有个问题。当未来微服务越来越多,大家都来调用
user-service
的接口,那么UserClient
就写了很多遍,重复开发。 -
现在,抽取出一个独立的模块
feign-api
,把接口有关的 POJO 、默认的 Feign 配置都放在这个模块中,提供给消费者使用。结构如下所示。 -
但是这种方式也有一个缺点,就是当消费者
order-service
只想调用feign-api
里的一两个方法,而把项目 jar 包整个引入就显得有点冗余了。 -
可见,两种最佳实践都并不是完美的。如果你在意面向契约编程,就采用方式一。如果你更在意耦合度,那就采用方式二。都要根据具体业务的实际情况决定。
1)创建模块
-
首先创建一个 module ,命名为
feign-api
,然后引入 feign 的 starter 依赖。 -
打开
pom.xml
文件,添加 Feign 的依赖。<!-- Feign远程调用客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2)迁移到feign-api
-
把
order-service
中的UserClient
、User
、DefaultFeignConfiguration
都复制到feign-api
项目中。 -
迁移前的
order-service
如下。 -
迁移后的
feign-api
如下。 -
order-service
迁移过去的文件就都可以删除了。
3)在消费者中引入feign-api依赖
-
order-service
中要引入feign-api
依赖。打开order-service
的pom.xml
。<!-- 引入自己写的feign的统一API --> <dependency> <groupId>cn.itcast.demo</groupId> <artifactId>feign-api</artifactId> <version>1.0</version> </dependency>
4)修改import
-
修改
order-service
中的所有与上述三个组件有关的 import 部分,改成导入feign-api
中的包。 -
OrderService
。
5)报错:UserFeign无法注入
-
启动
OrderApplication
时,发生了如下报错。Description: Field userClient in cn.itcast.order.service.OrderService required a bean of type 'cn.itcast.feign.clients.UserClient' that could not be found. Action: Consider defining a bean of type 'cn.itcast.feign.clients.UserClient' in your configuration.
-
这个报错,说明
UserClient
无法注入成功,证明UserClient
没有创建对象,所以 Spring 在容器中找不到它,从而注入失败。 -
之前可以成功运行,是因为
UserClient
在order-service
项目下,启动类OrderApplication.java
扫描到UserClient
中的注解@FeignClient("userservice")
,就可以创建UserClient
对象。 -
但是,Spring 中
order-service
项目默认扫描包的范围是其启动类所在的包,本例中只扫描cn.itcast.order
包。 -
而现在
UserClient
所在的包是cn.itcast.feign
。两者所在的包不一样,因此order-service
扫描不到。因此 Spring 无法为UserClient
创建对象。 -
当定义的
FeignClient
不在SpringBootApplication
的扫描包范围时,这些FeignClient
无法使用。这里有两种方式解决。 -
【解决方法一】在
OrderApplication.java
的注解@EnableFeignClients
中指定FeignClient
所在的包。@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
-
【(推荐) 解决方法二】在
OrderApplication.java
的注解@EnableFeignClients
中指定FeignClient
字节码,多个用逗号分隔。@EnableFeignClients(clients = { UserClient.class})