OpenFeign核心架构原理
原始Feign是什么样的?
在日常开发中,使用Feign很简单,就三步
第一步:引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
第二步:在启动引导类加上@EnableFeignClients
注解
@SpringBootApplication
@EnableFeignClients
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
第三步:写个FeignClient接口
@FeignClient(name = "order")
@RequestMapping("/order")
public interface OrderApiClient {
@GetMapping
Order queryOrder(@RequestParam("orderId") Long orderId);
}
之后当我们要使用时,只需要注入OrderApiClient
对象就可以了
虽然使用方便,但这并不是Feign最原始的使用方式,而是SpringCloud整合Feign之后的使用方式
Feign最开始是由Netflix开源的
后来SpringCloud就将Feign进行了一层封装,整合到自己的生态,让Feign使用起来更加简单
并同时也给它起了一个更高级的名字,OpenFeign
接下来文章表述有时可能并没有严格区分Feign和OpenFeign的含义,你知道是这么个意思就行了。
Feign本身有自己的使用方式,也有类似Spring MVC相关的注解,如下所示:
public interface OrderApiClient {
@RequestLine("GET /order/{orderId}")
Order queryOrder(@Param("orderId") Long orderId);
}
OrderApiClient对象需要手动通过Feign.builder()
来创建
public class FeignDemo {
public static void main(String[] args) {
OrderApiClient orderApiClient = Feign.builder()
.target(OrderApiClient.class, "http://localhost:8088");
orderApiClient.queryOrder(9527L);
}
}
Feign的本质:动态代理 + 七大核心组件
相信稍微了解Feign的小伙伴都知道,Feign底层其实是基于JDK动态代理来的
所以Feign.builder()
最终构造的是一个代理对象
Feign在构建动态代理的时候,会去解析方法上的注解和参数
获取Http请求需要用到基本参数以及和这些参数和方法参数的对应关系
比如Http请求的url、请求体是方法中的第几个参数、请求头是方法中的第几个参数等等
之后在构建Http请求时,就知道请求路径以及方法的第几个参数对应是Http请求的哪部分数据
当调用动态代理方法的时候,Feign就会将上述解析出来的Http请求基本参数和方法入参组装成一个Http请求
然后发送Http请求,获取响应,再根据响应的内容的类型将响应体的内容转换成对应的类型
这就是Feign的大致原理
在整个Feign动态代理生成和调用过程中,需要依靠Feign的一些核心组件来协调完成
如下图所示是Feign的一些核心组件
这些核心组件可以通过Feign.builder()
进行替换
由于组件很多,这里我挑几个重要的跟大家讲一讲
1、Contract
前面在说Feign在构建动态代理的时候,会去解析方法上的注解和参数,获取Http请求需要用到基本参数
而这个Contract接口的作用就是用来干解析这件事的
Contract的默认实现是解析Feign自己原生注解的
解析时,会为每个方法生成一个MethodMetadata对象
MethodMetadata就封装了Http请求需要用到基本参数以及这些参数和方法参数的对应关系
SpringCloud在整合Feign的时候,为了让Feign能够识别Spring MVC的注解,所以就自己实现了Contract接口
2、Encoder
通过名字也可以看出来,这个其实用来编码的
具体的作用就是将请求体对应的方法参数序列化成字节数组
Feign默认的Encoder实现只支持请求体对应的方法参数类型为String和字节数组
如果是其它类型,比如说请求体对应的方法参数类型为AddOrderRequest.class
类型,此时就无法对AddOrderRequest