【Spring Cloud】Feign最佳实践
前言
-
本次示例代码的文件结构如下图所示。 本文总结了 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})