OpenFeign 入门教程 - 基础篇(2024 年)
大纲
OpenFeign 基础使用
版本说明
在本文的所有案例中,各个组件统一使用以下版本:
组件名 | 版本 |
---|---|
Java | 17+ |
Spring Boot | 3.2.0 |
Spring Cloud | 2023.0.0 |
新版本支持的特性
新版本特性概览
- 支持 Sentinel 和它的 Fallback。
- 支持 Spring Cloud LoadBalancer 作为负载均衡客户端。
默认集成 LoadBalancer
由于 NetFlix Ribbon 的停更,Spring Cloud 官方推荐使用 Spring Cloud LoadBalancer 来替代 Spring Cloud Ribbon,详细说明请看 这里。从 Spring Cloud 2020.0 版本(即 Spring Cloud Alibaba 2.2.5 版本)开始,OpenFeign 就默认集成了 Spring Cloud LoadBalancer 作为客户端负载均衡组件,而且它是可选的依赖组件。因此,在使用 Spring Cloud OpenFeign 时,不需要额外引入 spring-cloud-starter-loadbalancer
依赖,客户端负载均衡功能就会默认启用。不过,如果希望自定义负载均衡策略或调整 Spring Cloud LoadBalancer 的配置,则可能需要明确引入 spring-cloud-starter-loadbalancer
依赖以便进行更细粒度的控制。
设置请求超时时间
在 OpenFeign 中,可以通过配置 connectTimeout
和 readTimeout
参数来指定请求超时时间,其中 connectTimeout
是连接超时时间,而 readTimeout
是请求处理超时时间。值得一提的是,新版本 OpenFeign 默认的请求处理超时时间是 60 秒,当服务端处理超过规定时间后,会导致 Feign 客户端抛出异常。
官方文档说明
在 OpenFeign 官方文档 中,配置参数说明如下:
官方文档说明
在 OpenFeign 官方文档 中,部分可配置参数列表如下:
全局设置生效
通过 default
在全局配置 Feign 的请求超时时间,所有的 FeignClient 都会应用生效。
1 | spring: |
局部设置生效
通过服务名称为特定的服务单独配置请求超时时间,单独配置的超时时间将会覆盖全局配置。
1 | spring: |
案例代码下载
代码下载
完整的案例代码可以从这里下载。
设置失败重试次数
在默认情况下,OpenFeign 会创建 Retryer.NEVERRETRY
类型为 Retryer 的 Bean,也就是说默认会禁用重试机制。请注意,这种重试行为与 Feign 的默认行为不同,它会自动重试 IOExceptions
,将它们视为与网络相关的瞬态异常,以及从 ErrorDecoder 抛出的任何 RetryableException
。
全局设置生效
若希望在全局设置 Feign 的失败重试次数,可以自定义一个 Retryer 的 Bean,并加载到 Spring IOC 容器中,如下所示:
1 |
|
又或者在 application.yml
中,直接指定全局使用哪个失败重试类(Retryer)
1 | spring: |
提示
使用 YML 配置文件的方式会调用 Retryer.Default
类的默认构造方法,效果相当于调用 new Retryer.Default(100, 1000, 5);
。
Retryer.Default(long period, long maxPeriod, int maxAttempts)
构造方法的参数说明如下:
period
:第一次重试之前的间隔时间,单位为毫秒maxPeriod
: 最大间隔时间,单位为毫秒maxAttempts
:最大请求次数
特别注意
在消费方(接口调用方)设置失败重试次数之后,IDE 控制台并不会看到多次重试过程,只会显示正确的返回结果,这是 OpenFeign 的日志打印问题导致的。如果希望重试效果明显一点,可以配置 OpenFeign 日志功能,将详细的重试日志打印出来;又或者自行打印接口开始调用到接口结束调用的时间差,以此观察失败重试机制是否生效。
局部设置生效
通过服务名称为特定的服务单独配置失败重试类(Retryer),此方式会覆盖全局配置的 Retryer。
- 首先定义一个失败重试配置类,特别注意,该配置类没有被
@Configuration
注解标注,不然该配置类默认会在全局生效
1 | public class FeignRetryerConfig { |
- 然后通过
@FeignClient
注解的value
和configuration
属性来指定服务名称和失败重试配置类,这样该服务只会使用指定的失败重试类(Retryer)
1 |
|
又或者在 application.yml
中,直接为特定的服务指定使用 Retryer.Default
失败重试类,如下所示:
1 | spring: |
提示
使用 YML 配置文件的方式会调用 Retryer.Default
类的默认构造方法,效果相当于调用 new Retryer.Default(100, 1000, 5);
。
案例代码下载
代码下载
完整的案例代码可以从这里下载。
自定义失败重试机制
常见的失败重试机制有以下三种:
固定间隔重试
:每次重试之间的时间间隔固定不变,例如每次重试之间相隔 1 秒。指数重试
:每次重试之间的时间间隔按指数递增。例如,初始时间间隔为 1 秒,每次重试后加倍,即第一次 1 秒,第二次 2 秒,第三次 4 秒,以此类推。随机间隔重试
:每次重试之间的时间间隔是随机的,通过引入随机性来防止多个失败请求同时发生。例如,每次重试的时间间隔在一定范围内随机选择。
自定义失败重试类
为了自定义失败重试机制,可以实现 Retryer 接口,并重写 continueOrPropagate()
方法。值得一提的是,continueOrPropagate()
方法是 Retryer 接口中最重要的方法,它接受一个 RetryableException 作为参数,且没有返回值。当执行这个方法时,它要么抛出一个异常,要么成功执行完(通常是在休眠一段时间后)。如果它没有抛出异常,Feign 将继续重试调用。如果抛出异常,该异常将被传播,从而有效地以错误形式结束方法调用。
1 | import feign.RetryableException; |
全局设置生效
为了让自定义失败重试类(Retryer)全局设置生效,可以将该 Retryer 的 Bean 加载到 Spring IOC 容器中,如下所示:
1 |
|
又或者在 application.yml
中,直接指定全局使用哪个自定义失败重试类(Retryer)
1 | spring: |
提示
使用 YML 配置文件的方式会调用 CustomRetryer
类的默认构造方法,效果相当于调用 new CustomRetryer(100, 3);
。
局部设置生效
通过服务名称为特定的服务单独配置自定义失败重试类(Retryer),此方式会覆盖全局配置的 Retryer。
- 首先定义一个失败重试配置类,特别注意,该配置类没有被
@Configuration
注解标注,不然该配置类默认会在全局生效
1 | public class FeignRetryerConfig { |
- 然后通过
@FeignClient
注解的value
和configuration
属性来指定服务名称和失败重试配置类,这样该服务只会使用指定的自定义失败重试类(Retryer)
1 |
|
又或者在 application.yml
中,直接为特定的服务指定使用哪个自定义失败重试类(Retryer)
1 | spring: |
提示
使用 YML 配置文件的方式会调用 CustomRetryer
类的默认构造方法,效果相当于调用 new CustomRetryer(100, 3);
。
案例代码下载
代码下载
完整的案例代码可以从这里下载。
Spring Retry 使用
除了可以使用 OpenFeign 自身提供的失败重试机制,还可以使用 Spring Retry 组件来实现,它提供了 @Retryable
、@Backoff
等注解。值得一提的是,Spring Retry 的底层是基于 AOP 来实现的,这里不再累述。
替换默认 Http 客户端
OpenFeign 中的 HttpClient 如果不做特殊配置,底层默认会使用 JDK 原生的 HttpURLConnection 发送 HTTP 请求。由于默认的 HttpURLConnection 没有连接池,性能和效率比较低,如果采用默认的,那么对性能会造成较大影响。值得一提的是,OpenFeign 支持使用 Apache HttpClient 和 Okhttp 来替换 JDK 原生的 HttpURLConnection。
特别注意
从 Spring Cloud OpenFeign 4 开始,官方不再支持 Feign Apache HttpClient 4,建议改用 Apache HttpClient 5,官方文档 说明如下图所示:
Apache HttpClient 替换
替换步骤
- 引入以下依赖
1 | <!-- feign hc 5 --> |
- 启用 Apache HttpClient 5
1 | spring: |
Apache HttpClient 5 的自动配置类
在 OpenFeign 中,Apache HttpClient 的自动配置类有两个,分别是 HttpClient5FeignConfiguration
与 HttpClient5FeignLoadBalancerConfiguration
。
验证替换
在 HttpClient5FeignLoadBalancerConfiguration.feignClient()
方法内打上断点(约 63 行),重新启动项目(切记不要以单元测试的方式启动,否则可能会因缺少配置导致无法进入打断点的代码),此时可以看到确实进行了 ApacheHttpClient 的声明;再将 spring.cloud.openfeign.httpclient.hc5.enabled
设置为 false
后,断点就进不来了,由此可以验证 ApacheHttpClient 替换成功。另外,从异常堆栈信息也可以看出 ApacheHttpClient 是否替换成功,如下图所示:
案例代码下载
代码下载
完整的案例代码可以从这里下载。
Okhttp 替换
替换步骤
- 引入以下依赖
1 | <!-- Okhttp --> |
- 启用 Okhttp
1 | spring: |
Okhttp 的自动配置类
在 OpenFeign 中,Okhttp 的自动配置类有两个,分别是 OkHttpFeignConfiguration
与 OkHttpFeignLoadBalancerConfiguration
,都默认带有连接池功能。
自定义拦截器
为了方便接口调试,对请求和响应进行日志打印,可以增加以下 Okhttp 拦截器配置。
1 |
|
验证替换
在 OkHttpFeignLoadBalancerConfiguration.feignClient()
方法内打上断点(约 58 行),然后正常启动项目(切记不要以单元测试的方式启动,否则可能会因缺少配置导致无法进入打断点的代码),此时可以看到确实进行了 OkHttpClient 的声明;再将 spring.cloud.openfeign.okhttp.enabled
设置为 false
后,断点就进不来了,由此可以验证 OkHttpClient 替换成功。另外,从异常堆栈信息也可以看出 Okhttp 是否替换成功,如下图所示:
案例代码下载
代码下载
完整的案例代码可以从这里下载。
开启请求 / 响应 GZIP 压缩
参数说明
Spring Cloud OpenFeign 支持对 HTTP 请求和响应进行 GZIP 压缩,以减少通信过程中的性能损耗。官方文档的说明如下图所示:
通过下面的两个参数设置,就能开启请求与响应的压缩功能:
1 | true = |
还可以对请求压缩做一些更细致的配置,比如下面的配置内容指定了压缩的请求数据类型,并设置了请求压缩的大小下限,只有超过这个大小的请求才会进行压缩:
1 | # 启用请求压缩 |
配置示例
完整的配置示例如下:
1 | spring: |
开启日志打印功能
OpenFeign 提供了日志打印功能,开发者可以通过配置来调整日志级别,从而了解 Feign 中 Http 请求的细节。简而言之,就是对 Feign 接口的调用情况进行监控和输出。
日志级别
OpenFeign 支持的日志级别如下:
NONE
:默认的日志级别,不打印任何日志。BASIC
:仅记录请求方法、URL、响应状态码及执行时间。HEADERS
:除了 BASIC 中定义的日志信息之外,还有请求和响应的头信息。FULL
:除了 HEADERS 中定义的日志信息之外,还有请求和响应的正文及元数据。
使用步骤
定义日志级别 Bean
1 | import feign.Logger; |
在 YML 配置文件中,配置 Feign 客户端的日志输出。特别注意,Feign 日志记录仅响应 DEBUG
日志级别的配置。
1 | logging: |
如果开启了请求 / 响应 GZIP 压缩,那么控制台输出的日志信息如下:
1 | [http-nio-8021-exec-1] DEBUG com.turing.cloud.api.PayFeignApi - [PayFeignApi#getAppInfo] ---> GET http://cloud-payment-service/pay/get HTTP/1.1 |
如果配置了失败重试次数,那么控制台输出的日志信息如下:
1 | [http-nio-8021-exec-1] DEBUG com.turing.cloud.api.PayFeignApi - [PayFeignApi#getAppInfo] ---> RETRYING |