Skip to content

OpenFeign 简介

1. 概述

近期在工作中,有一个 HTTP 请求外部系统的需求,当时脑海中首先想到的就是使用 OkHttp3 框架,封装一个 HTTP 请求工具类;但是偶然间发现,使用 OpenFeign 不仅可以实现调用微服务,也可以指定 url 进行 HTTP 请求,相比之前,OpenFeign 使用更简单,开发更简单明了;所以,现在就对 OpenFeign 进行全面的学习下。

2. OpenFeign 介绍

OpenFeign 是一个显示声明式的 WebService 客户端。使用 OpenFeign 能让编写 Web Service 客户端更加简单。使用时只需定义服务接口,然后在上面添加注解。OpenFeign 也支持可拔插式的编码和解码器。Spring Cloud 对 Feign 进行了封装,使其支持 MVC 注解和 HttpMessageConverts。和 Eureka(服务注册中心)、Ribbon 组合可以实现负载均衡。在 Spring Cloud 中使用 OpenFeign,可以做到使用 HTTP 请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问 HTTP 请求,非常的方便。

OpenFeign 的设计宗旨式简化 Java Http 客户端的开发。Feign 在 RestTemplate 的基础上做了进一步的封装,由其来帮助我们定义和实现依赖服务接口的定义。在 OpenFeign 的协助下,我们只需创建一个接口并使用注解的方式进行配置(类似于 Dao 接口上面的 Mapper 注解)即可完成对服务提供方的接口绑定,大大简化了 Spring cloud Ribbon 的开发,自动封装服务调用客户端的开发量。

OpenFeign 集成了 Ribbon,利用 ribbon 维护了服务列表,并且通过 ribbon 实现了客户端的负载均衡。与 ribbon 不同的是,通过 OpenFeign 只需要定义服务绑定接口且以申明式的方法,优雅而简单的实现了服务调用。

3. 基础使用

  1. pom.xml 引用
xml
<!--Open feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 启用 OpenFeign,在启动类上增加 @EnableFeignClients 注解
java

@SpringBootApplication
@EnableFeignClients
public class OpenFeignMain {
    public static void main(String[] args) {
        SpringApplication.run(OpenFeignMain.class, args);
    }
}
  1. 编写接口,即远程服务调用的接口
java

@Component
//添加 @FeignClient 注解即可绑定服务提供者
@FeignClient(value = "test-service")
public interface TestService {
    @GetMapping("/test/user/list")
    ResultDto list();
}

@FeignClient(value = "test-service") 中的 test-service 即调用的微服务在注册中心注册的名称

@GetMapping 即调用的服务的URL地址,使用 POST 方式调用,也支持 POST 等方式

  1. 调用
java

@RestController
@RequestMapping("/consumer")
public class TestController {

    @Autowired
    private TestService testService;

    @GetMapping("/list")
    public ResultDto list() {
        return testService.list();
    }
}

4. 参数配置

4.1 超时控制

OpenFeign 默认超时时间为 1s,超过 1s 就会返回错误页面。如果我们的接口处理业务确实超过 1s,就需要对接口进行超时配置,如下:

yml
#设置feign客户端连接所用的超时时间,适用于网络状况正常情况下,两端连接所用时间
ribbon:
  #指的是建立连接所用时间
  ReadTimeout: 1000
  #指建立连接后从服务读取到可用资源所用时间
  ConnectTimeout: 1000

4.2 日志增量

通过指定 feign.Logger 的日志级别参数来控制日志输出:

java
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenFeignConfig {
    @Bean
    Logger.Level feignLogLevel() {
        return Logger.Level.FULL;
    }
}

日志级别有以下几种:

  • NONE:默认,不显示任何日志;

  • BASIC: 仅记录请求方法、URL、响应状态码及执行时间;

  • HEADERS:除了 BASIC 中定义的信息之外,还有请求头和响应头信息;

  • FULL:除了 HEADERS 中定义的信息之外,还有请求的正文和响应数据。

以上是通过代码的形式进行配置,也可以直接通过配置文件的方式指定日志级别,如下所示:

yml
logging:
  level:
    com.demo.feign.TestService: DEBUG

feign:
  # Feign 客户端配置,对应 FeignClientProperties 配置属性类
  client:
    # config 配置项是 Map 类型。key 为 Feign 客户端的名字,value 为 FeignClientConfiguration 对象
    config:
      # 全局级别配置
      default:
        logger-level: BASIC
      # 客户端级别配置
      demo-provider:
        logger-level: FULL

5. 单独使用

在使用 Spring Cloud 的项目中,我们大多数是通过 Feign 调用从 Ribbon 负载均衡选择的服务实例,而 Ribbon 是通过注册中心获取到的服务实例列表。但是有些场景下,可能想要单独使用 Feign 调用,比如调用第三方服务,或者调用的虽然是内部服务,但是并没有注册到注册中心。这个时候就需要直接指定服务的 IP 地址等信息,进行直接的调用。

java
//@FeignClient(name = "demo-provider")
@FeignClient(name = "iocoder", url = "http://www.iocoder.cn")
public interface DemoProviderFeignClient {

    //@GetMapping("/echo")
    //String echo(@RequestParam("name") String name);

    @GetMapping("/")
    String echo(@RequestParam("name") String name);
}

@FeignClient 注解的 url 属性设置要调用的服务的地址即可。

6. HTTP 客户端

默认情况下,Feign 通过 JDK 自带的 HttpURLConnection 封装了 Client.Default,实现 HTTP 调用的客户端。因为 HttpURLConnection 缺少对 HTTP 连接池的支持,性能较低,因此 Feign 提供了另外两个 HTTP 客户端:

  • ApacheHttpClient,基于 Apache HttpClient 封装

  • OkHttpClient,基于 OkHttp 封装

6.1 使用 Apache HttpClient

  1. 引入 feign-httpclient 依赖
xml
<!-- 引入 Feign Apache HttpClient 依赖 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>
  1. 修改配置
yml
feign:
  # Feign Apache HttpClient 配置项,对应 FeignHttpClientProperties 配置属性类
  httpclient:
    #是否开启,默认为 true
    enabled: true
    #最大连接数,默认为 200
    max-connections: 200
    #每个路由的最大连接数,默认为 50
    max-connections-per-route: 50

虽然说 feign.httpclient.enable 默认为 true 开启,但是还是需要引入 feign-httpclient 依赖,才能创建 ApacheHttpClient 对象

6.2 使用 OkHttpClient

  1. 引入 feign-okhttp 依赖
xml
<!-- 引入 Feign Apache HttpClient 依赖 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>
  1. 修改配置
yml
feign:
  httpclient:
    #是否开启,默认为 true
    enabled: false
  okhttp:
    #是否开启,默认为 false
    enabled: true

7. 请求重试

Feign 和 Ribbon 都有请求重试的功能,两者都启用该功能的话,会产生冲突的问题。因此,有且只能启动一个的重试。目前比较推荐的是使用 Ribbon 来提供重试。

在 Spring Cloud OpenFeign 中,默认创建的是 NEVER_RETRY 不进行重试,因此我们只需要配置 Ribbon 的重试功能即可。

yml
ribbon:
  #请求的连接超时时间,单位:毫秒。默认为 1000
  ConnectTimeout: 1000
  #请求的读取超时时间,单位:毫秒。默认为 1000
  ReadTimeout: 1
  #是否对所有操作都进行重试,默认为 false。
  OkToRetryOnAllOperations: true
  #对当前服务的重试次数,默认为 0 次。
  MaxAutoRetries: 0
  #重新选择服务实例的次数,默认为 1 次。注意,不包含第 1 次
  MaxAutoRetriesNextServer: 1