OpenFeign 开发随笔
OpenFeign 版本问题
是否默认集成 Ribbon
在 Spring Cloud 早期版本(Hoxton 及更早),OpenFeign 和 Ribbon 有紧密的集成关系,如下所示:
Spring Cloud
Hoxton及以前版本- 默认集成 Ribbon
- OpenFeign 默认使用 Ribbon 作为客户端负载均衡工具。
- 当使用
@FeignClient时,底层会自动通过 Ribbon 来选择目标服务实例。 - Ribbon 自动从 Eureka 或 Nacos 等注册中心获取服务列表,然后通过负载均衡算法(默认轮询)选择实例发起请求。
- 依赖关系
- 在
spring-cloud-starter-openfeign中,Ribbon 依赖会自动传递进来,用户无需手动引入 Ribbon 依赖。
- 在
- 默认集成 Ribbon
Spring Cloud
2020+版本(包括 Spring Cloud Alibaba2021+版本)- Ribbon 已被弃用,OpenFeign 不再内置 Ribbon。
- 取而代之的是 Spring Cloud LoadBalancer,新的默认负载均衡组件。
- 如果想继续用 Ribbon,需要手动引入 Ribbon 依赖并配置。
| 版本 | 负载均衡(Ribbon) | 默认行为 |
|---|---|---|
Spring Cloud Hoxton 及以前 | 默认集成 | Ribbon 自动生效 |
Spring Cloud 2020+ | 已弃用 → 使用 Spring Cloud LoadBalancer 替代 | 新方案默认生效,老方案失效 |
是否默认集成 Hystrix
在 Spring Cloud 早期版本(Hoxton 及更早),OpenFeign 和 Hystrix 有紧密的集成关系,但默认行为会因为 Spring Cloud 版本不同而变化。OpenFeign 和 Hystrix 的关系如下:
Spring Cloud
Hoxton及以前版本- OpenFeign 默认集成了 Hystrix,但 Hystrix 默认是关闭的。
- 如果想在 Feign 中使用熔断,需要显式配置开启,也就是在配置文件中添加
feign.hystrix.enabled=true
Spring Cloud
2020+版本(包括 Spring Cloud Alibaba2021+版本)- Hystrix 被彻底弃用,官方建议使用 Resilience4j 替代。
- 即便开启了
feign.hystrix.enabled=true,也不会生效,因为 Feign 已经移除了对 Hystrix 的直接支持。 - 如果需要熔断,可以通过 Spring Cloud CircuitBreaker + Resilience4j 或 Sentinel 实现。
| 版本 | 熔断(Hystrix) | 默认行为 |
|---|---|---|
Spring Cloud Hoxton 及以前 | 默认集成,但默认关闭 | Hystrix 需要手动启用 |
Spring Cloud 2020+ | 已弃用 → 使用 Resilience4j 替代 | 新方案默认生效,老方案失效 |
OpenFeign 底层实现原理
失败重试机制的底层实现原理

- (1) 添加注解
- 在主启动类或者配置类上添加
@EnableFeignClients注解。
- 在主启动类或者配置类上添加
- (2) 动态代理
@EnableFeignClients注解会触发 SpringBoot 框架的自动配置机制,扫描所有标记有@FeignClient的接口,并为它们创建代理实例。
- (3) RequestTemplate 发送 HTTP 请求
- 此处的 RequeustTemplate 可以理解为 RestTemplate,因为两者的目的相同。
- OpenFeign 不能直接发送 HTTP 请求,它在动态代理里面做了一些事情,也就是将注解里面请求的路由地址取出来,然后拼接出来一个 URL 请求的地址,然后再使用 RequestTemplate(RestTemplate)去发送 HTTP 请求。
- (4) RestTemplate 依靠 HTTP 框架实现 Web 请求的发送
- RestTemplate 只是一个模板方法类,它只是规定了一些调用的 API,底层并没有真正的实现,它依靠 HTTP 框架实现 Web 请求的发送(比如 Apache Http Client、Okhttp)。
OpenFeign 整合第三方框架
整合 Sentinel 失败
错误描述
使用以下组件版本将 OpenFeign 整合 Sentinel:
| 组件 | 版本 | 说明 |
|---|---|---|
| Spring Boot | 3.2.0 | |
| Spring Cloud | 2023.0.0 | |
| Spring Cloud Alibaba | 2022.0.0.0 |
在微服务应用启动时,会抛出了以下异常信息:
1 | Caused by: java.lang.IllegalStateException: Method ProviderFeignApi#getPayByOrderNumber(String) not annotated with HTTP method type (ex. GET, POST) |
错误分析
微服务应用启动失败的原因是 Spring Boot 和 SpringCloud 的版本过高,导致 Spring Cloud Alibaba Sentinel 与 OpenFeign 不兼容。
第一种解决办法
耐心等待 Spring Cloud Alibaba 官方适配高版本的 Spring Boot 和 SpringCloud,从而解决版本兼容问题。
第二种解决办法
降低 Spring Boot 和 SpringCloud 的版本,比如使用以下组件版本:
| 组件 | 版本 | 说明 |
|---|---|---|
| Spring Boot | 3.0.9 | |
| Spring Cloud | 2022.0.2 | |
| Spring Cloud Alibaba | 2022.0.0.0 |
第三种解决方案
重写 com.alibaba.cloud.sentinel.feign.SentinelFeignAutoConfiguration 自动配置类,最关键的是重写 feign.Feign.Builder 类的 internalBuild() 方法,并在 SentinelFeignAutoConfiguration 类加载前将重写的自动配置类注入到 Spring IOC 容器中。值得一提的是,修复版本兼容问题的完整案例代码可以从 这里 下载得到,并且 OpenFeign 整合 Sentinel 的详细教程还可以看 这里。
参考项目
OpenFeign 常见的使用错误
Request method ‘POST’ not supported
- 错误信息:在调用 OpenFeign 下面这段代码时,抛出了
Request method 'POST' not supported的异常
1 | /** |
1 | /** |
- 错误原因:OpenFeign 原生的连接工具默认使用了 JDK 中的
HttpURLConnection类进行实现,下面这段代码是在HttpURLConnection中发现的,所以只要 HTTP 请求里有 Body 体对象,就会强制的把 GET 请求转换成 POST 请求。
1 | private synchronized OutputStream getOutputStream0() throws IOException { |
- 第一种解决方案:不使用 POJO 对象作为参数,而是传入多个独立的参数,并添加
@RequestParam注解
1 | /** |
- 第二种解决方案:使用 POJO 对象作为参数,同时添加
@SpringQueryMap注解
1 | /** |
提示
Feign 的 @QueryMap 注解支持将 POJO 用作 GET 请求的参数映射,但默认的 @QueryMap 注解与 Spring 不兼容,因为它缺少 value 属性。Spring Cloud OpenFeign 提供了等效的 @SpringQueryMap 注解,用于将 POJO 或 Map 参数映射为查询参数。简而言之,Feign 的 GET 请求无法解析对象参数,如果传参是一个类对象,框架就需要把这个类对象解析成查询参数,但是直接在方法中传参框架不会自动把类对象解析成查询参数。@SpringQueryMap 注解的作用就是把 POJO 解析成 k1=v1&k2=v2 的查询参数格式。
- 第三种解决方案:使用 Apache HttpClient 或者 OkHttp 替换掉 OpenFeign 原生使用的
HttpURLConnection连接工具,然后添加@RequestBody注解
1 | /** |
warning
笔者尝试使用 Apache HttpClient 或者 OkHttp 替换 OpenFeign 默认使用的 HttpURLConnection,但并没有生效,有兴趣的可以参考这里的 替换教程。
