在学习OpenFeign前我们先了解下Feign。Netflix Feign 是 Netflix 公司发布的一种实现负载均衡和服务调用的开源组件。 Feign 对 Ribbon 进行了集成,利用 Ribbon 维护了一份可用服务清单,并通过 Ribbon 实现了客户端的负载均衡。 Feign 是一种声明式服务调用组件,它在 RestTemplate 的基础上做了进一步的封装。通过 Feign,我们只需要声明一个接口并通过注解进行简单的配置(类似于 Dao 接口上面的 Mapper 注解一样)即可实现对 HTTP 接口的绑定。我们可以像调用本地方法一样来调用远程服务,而完全感觉不到这是在进行远程调用。 Feign 支持多种注解,例如 Feign 自带的注解以及 JAX-RS 注解等,但遗憾的是 Feign 本身并不支持 Spring MVC 注解。 2019 年 Netflix 公司宣布 Feign 组件正式进入停更维护状态,于是 Spring 官方便推出了一个名为 OpenFeign 的组件作为 Feign 的替代方案。

OpenFeign简介

OpenFeign 全称 Spring Cloud OpenFeign, Spring 官方推出的一种声明式服务调用与负载均衡组件,它的出现就是为了替代进入停更维护状态的 Feign。 OpenFeign 是 Spring Cloud 对 Feign 的二次封装,它具有 Feign 的所有功能,并在 Feign 的基础上增加了对 Spring MVC 注解的支持,例如 @RequestMapping、@GetMapping 和 @PostMapping 等。 OpenFeign 常用注解
注解 说明
@FeignClient 该注解用于通知 OpenFeign 组件对 @RequestMapping 注解下的接口进行解析,并通过动态代理的方式产生实现类,实现负载均衡和服务调用。
@EnableFeignClients 该注解用于开启 OpenFeign 功能,当 Spring Cloud 应用启动时,OpenFeign 会扫描标有 @FeignClient 注解的接口,生成代理并注册到 Spring 容器中。
@RequestMapping Spring MVC 注解,在 Spring MVC 中使用该注解映射请求,通过它来指定控制器(Controller)可以处理哪些 URL 请求,相当于 Servlet 中 web.xml 的配置。
@GetMapping Spring MVC 注解,用来映射 GET 请求,它是一个组合注解,相当于 @RequestMapping(method = RequestMethod.GET) 。
@PostMapping Spring MVC 注解,用来映射 POST 请求,它是一个组合注解,相当于 @RequestMapping(method = RequestMethod.POST) 。
Feign VS OpenFeign 相同点 Feign 和 OpenFegin 具有以下相同点:
  • Feign 和 OpenFeign 都是 Spring Cloud 下的远程调用和负载均衡组件。
  • Feign 和 OpenFeign 作用一样,都可以实现服务的远程调用和负载均衡。
  • Feign 和 OpenFeign 都对 Ribbon 进行了集成,都利用 Ribbon 维护了可用服务清单,并通过 Ribbon 实现了客户端的负载均衡。
  • Feign 和 OpenFeign 都是在服务消费者(客户端)定义服务绑定接口并通过注解的方式进行配置,以实现远程服务的调用。
不同点 Feign 和 OpenFeign 具有以下不同:
  • Feign 和 OpenFeign 的依赖项不同,Feign 的依赖为 spring-cloud-starter-feign,而 OpenFeign 的依赖为 spring-cloud-starter-openfeign。
  • Feign 和 OpenFeign 支持的注解不同,Feign 支持 Feign 注解和 JAX-RS 注解,但不支持 Spring MVC 注解;OpenFeign 除了支持 Feign 注解和 JAX-RS 注解外,还支持 Spring MVC 注解。
OpenFeign 和 Feign 区别可以参考这篇文章:Ribbon和OpenFeign_皆非的万事屋的博客-CSDN博客_openfeign ribbon # OpenFeign远程服务调用 通过一个案例操作,演示下OpenFeign 是如何实现远程服务调用的。
  1. 首先创建一个<font style="color:rgb(68, 68, 68);">OpenFeign</font>模块 spring-cloud-openfeign-consumer-9006(消费者)

Spring Cloud OpenFeign - 图1

  1. pom依赖引入
  1. <!--添加 OpenFeign 依赖-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-openfeign</artifactId>
  5. </dependency>
  1. 类路径(即 /resources 目录)下,添加一个 <font style="color:rgb(68, 68, 68);">application.yml</font>,配置内容如下
  1. server:
  2. port: 9006
  3. spring:
  4. application:
  5. name: spring-cloud-openfeign-consumer-9006
  6. eureka:
  7. client:
  8. #表示是否将自己注册进 EurekaServer默认为true。
  9. register-with-eureka: true
  10. #是否从 EurekaServer 抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
  11. fetchRegistry: true
  12. service-url:
  13. defaultZone: http://127.0.0.1:9001/eureka
  1. 在启动类同路径下创建service包,然后在里面创建一个名为 BookService的接口,并在该接口上使用 **<font style="color:#E8323C;">@FeignClient </font>**注解实现对服务接口的绑定,代码如下
  1. //添加为容器内的一个组件
  2. @Component
  3. @FeignClient(value = "SPRING-CLOUD-EUREKA-PROVIDER-BOOK-9002")
  4. public interface BookService {
  5. //对应服务提供者(8002、9002)Controller 中定义的方法
  6. @RequestMapping(value = "/book/get/{id}", method = RequestMethod.GET)
  7. public Book get(@PathVariable("id") int id);
  8. @RequestMapping(value = "/book/list", method = RequestMethod.GET)
  9. public List<Book> selectAll();
  10. }
在编写服务绑定接口时,需要注意以下 2 点:
  • 在 @FeignClient 注解中,value 属性的取值为:服务提供者的服务名,即服务提供者配置文件(application.yml)中 spring.application.name 的取值。
  • 接口中定义的每个方法都与服务提供者(即 spring-cloud-eureka-provider-book-8002spring-cloud-eureka-provider-book-9002(还是复用前面所学的集群哦))中 Controller 定义的服务方法对应。
  1. 创建Controller类
  1. @RestController
  2. @Slf4j
  3. public class BookController {
  4. @Autowired
  5. private BookService bookService; //这里直接使用openfigen绑定的服务进行请求
  6. @GetMapping(value = "/book/get/{id}")
  7. public Book get(@PathVariable("id") int id) {
  8. return bookService.get(id);
  9. }
  10. @GetMapping(value = "/book/list")
  11. public List<Book> list() {
  12. return bookService.selectAll();
  13. }
  14. }
  1. 主启动类添加 @EnableFeignClients 注解开启 OpenFeign 功能
  1. @SpringBootApplication
  2. @EnableFeignClients
  3. public class SpringCloudOpenfeignConsumer9006Application {
  4. public static void main(String[] args) {
  5. SpringApplication.run(SpringCloudOpenfeignConsumer9006Application.class, args);
  6. }
  7. }

Spring Cloud 应用在启动时,OpenFeign 会扫描标有 @FeignClient 注解的接口生成代理,并注人到 Spring 容器中。

  1. 依次启动服务注册中心集群、服务提供者以及 spring-cloud-openfeign-consumer-9006,启动完访问 http://127.0.0.1:9004/book/get/1 结果如下

Spring Cloud OpenFeign - 图2Spring Cloud OpenFeign - 图3

即实现了远程调用,又实现了负载均衡调用,多次刷新通过source即可看出,默认轮训调用到不同服务器。

OpenFeign超时控制

OpenFeign 客户端的默认超时时间为 1 秒钟,如果服务端处理请求的时间超过 1 秒就会报错。为了避免这样的情况,我们需要对 OpenFeign 客户端的超时时间进行控制。 通过一个实例,来演示 OpenFeign 是如何进行超时控制的。
  1. 在所有的服务提供者(服务端)的 <font style="color:rgb(68, 68, 68);">BookController </font>中添加一个响应时间为 5 秒的服务,代码如下。
  1. //超时测试,该服务的响应时间为 5 秒
  2. @RequestMapping(value = "/book/feign/timeout")
  3. public String BookFeignTimeout() {
  4. try {
  5. TimeUnit.SECONDS.sleep(5);
  6. } catch (InterruptedException e) {
  7. e.printStackTrace();
  8. }
  9. return "spring-cloud-eureka-provider-book-9002";
  10. }
  1. spring-cloud-openfeign-consumer-9006 的 BookService 接口中添加以下代码,绑定服务端刚刚添加的超时服务。
  1. @RequestMapping(value = "/book/feign/timeout")
  2. public String BookFeignTimeout();
  1. spring-cloud-openfeign-consumer-9006 的 BookController接口中添加以下代码,绑定服务端刚刚添加的超时服务。
  1. @RequestMapping(value = "/book/feign/timeout")
  2. public String bookFeignTimeout(){
  3. return bookService.bookFeignTimeout();
  4. }
  1. feign:
  2. client:
  3. config:
  4. default:
  5. #指的是建立连接后从服务器读取到可用资源所用的时间
  6. ConnectTimeOut: 7000
  7. #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  8. ReadTimeOut: 7000

配置完毕后即可调整超时时间请求我们所编写的超时服务,看是否生效

OpenFeign日志增强

OpenFeign 提供了日志打印功能,我们可以通过配置调整日志级别,来了解请求的细节。 Feign 为每一个 FeignClient 都提供了一个 feign.Logger 实例,通过它可以对 OpenFeign 服务绑定接口的调用情况进行监控。 OpenFeign 日志打印功能的开启方式比较简单,下面我们就通过一个实例进行演示。
  1. 修改模块 spring-cloud-openfeign-consumer-9006配置文件
  1. logging:
  2. level:
  3. #feign 日志以什么样的级别监控该接口
  4. com.chen.springcloudopenfeignconsumer9006.service.BookService: debug
以上配置说明如下:
  • com.chen.springcloudopenfeignconsumer9006 是开启 @FeignClient 注解的接口(即服务绑定接口)的完整类名。也可以只配置部分路径,表示监控该路径下的所有服务绑定接口
  • debug:表示监听该接口的日志级别。
以上配置的含义就是,OpenFeign 以 debug 级别监控 com.chen.springcloudopenfeignconsumer9006 接口。
  1. 创建配置类

在config包中创建ConfigBean

  1. @Configuration
  2. public class ConfigBean {
  3. /**
  4. * OpenFeign 日志增强
  5. * 配置 OpenFeign 记录哪些内容
  6. */
  7. @Bean
  8. Logger.Level feginLoggerLevel() {
  9. return Logger.Level.FULL;
  10. }
  11. }
该配置的作用是通过配置的 Logger.Level 对象告诉 OpenFeign 记录哪些日志内容。 Logger.Level 的具体级别如下:
  • NONE:不记录任何信息。
  • BASIC:仅记录请求方法、URL 以及响应状态码和执行时间。
  • HEADERS:除了记录 BASIC 级别的信息外,还会记录请求和响应的头信息。
  • FULL:记录所有请求与响应的明细,包括头信息、请求体、元数据等等。
  1. 启动spring-cloud-openfeign-consumer-9006访问 http://127.0.0.1:9006/book/get/1。去ieda控制台可以查看如下日志信息,至此日志管理配置完毕。
  1. 2022-10-11 10:26:23.565 DEBUG 92748 --- [nio-9006-exec-4] c.c.s.service.BookService : [BookService#get] ---> GET http://SPRING-CLOUD-EUREKA-PROVIDER-BOOK-9002/book/get/1 HTTP/1.1
  2. 2022-10-11 10:26:23.566 DEBUG 92748 --- [nio-9006-exec-4] c.c.s.service.BookService : [BookService#get] ---> END HTTP (0-byte body)
  3. 2022-10-11 10:26:23.583 DEBUG 92748 --- [nio-9006-exec-4] c.c.s.service.BookService : [BookService#get] <--- HTTP/1.1 200 (17ms)
  4. 2022-10-11 10:26:23.583 DEBUG 92748 --- [nio-9006-exec-4] c.c.s.service.BookService : [BookService#get] connection: keep-alive
  5. 2022-10-11 10:26:23.583 DEBUG 92748 --- [nio-9006-exec-4] c.c.s.service.BookService : [BookService#get] content-type: application/json
  6. 2022-10-11 10:26:23.583 DEBUG 92748 --- [nio-9006-exec-4] c.c.s.service.BookService : [BookService#get] date: Tue, 11 Oct 2022 02:26:23 GMT
  7. 2022-10-11 10:26:23.583 DEBUG 92748 --- [nio-9006-exec-4] c.c.s.service.BookService : [BookService#get] keep-alive: timeout=60
  8. 2022-10-11 10:26:23.584 DEBUG 92748 --- [nio-9006-exec-4] c.c.s.service.BookService : [BookService#get] transfer-encoding: chunked
  9. 2022-10-11 10:26:23.584 DEBUG 92748 --- [nio-9006-exec-4] c.c.s.service.BookService : [BookService#get]
  10. 2022-10-11 10:26:23.584 DEBUG 92748 --- [nio-9006-exec-4] c.c.s.service.BookService : [BookService#get] {"id":"1","name":"《西游记》","author":"吴承恩","price":"55","publishDate":"2022-09-26 00:00:00","count":10,"source":"spring-cloud-eureka-provider-book-8002"}
  11. 2022-10-11 10:26:23.584 DEBUG 92748 --- [nio-9006-exec-4] c.c.s.service.BookService : [BookService#get] <--- END HTTP (166-byte body)

上方是通过类+配置的方式配置好的,我们也可以通过纯配置的方式配置,配置信息如下:

  1. # 开启feign的日志监控
  2. feign:
  3. client:
  4. config:
  5. default.loggerLevel: FULL
  6. logging:
  7. level:
  8. # feign日志以什么级别监控哪个接口
  9. cn.ideal.springcloud.service.PaymentFeignService: debug