OpenFeign 开发随笔
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
,但并没有生效,有兴趣的可以参考这里的 替换教程。