Feign的本质: 动态代理 + 七大核心组件
Feign底层是基于JDK动态代理来的, Feign.builder()最终构造的是一个代理对象, Feign在构建对象的时候会解析方法上的注解和参数, 获取Http请求需要用到基本参数以及和这些参数和方法参数的对应关系。然后发送Http请求, 获取响应, 再根据响应的内容的类型将响应体的内容转换成对应的类型。
#feign.Feign.Builder:



这些核心组件可以通过Feign.builder()进行替换。
- Contract
- Encoder
- Decoder
- Client
- InvocationHandlerFactory
- RequestInterceptor
- Retryer
文章目录
1.Contract

解析方法上的注解和参数, 获取Http请求需要用到基本参数。
Contract的默认实现是解析Feign自己原生注解的。

会为每个方法生成一个MethodMetadata对象。

MethodMetadata就封装了Http请求需要用到基本参数以及这些参数和方法参数的对应关系。
SpringCloud在整合Feign的时候, 为了让Feign能够识别Spring MVC的注解, 所以就自己实现了Contract接口。


2.Encoder
作用就是将请求体对应的方法参数序列化成字节数组。


Feign默认的Encoder实现只支持请求体对应的方法参数类型为String和字节数组。

如果是其他类型的话, 无法对对象进行序列化, 所以Spring就实现了Encoder接口。


可以将任意请求体对应的方法参数类型对象序列化成字节数组。
3.Decoder
Decoder其实就是将响应体由字节流反序列化成方法返回值类型的对象。


Spring也同样实现了Decoder。


可以将响应体对应的字节流反序列化成任意返回值类型对象。
4.Client
动态代理对象最终用来执行Http请求的组件。

默认实现为JDK的HttpURLConnection。

Feign还提供了基于HttpClient实现。

开启ApacheHttpClient发连接。
xml
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3</version>
</dependency>
<!-- feign-hc5-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hc5</artifactId>
<version>13.1</version>
</dependency>

基于负载均衡的实现:

根据服务名, 从ibbon中获取一个服务实例的信息, ip和端口号。之后会通过ip和端口向服务实例发送Http请求。
5.InvocationHandlerFactory
InvocationHandler的invoke方法实现就是动态代理走的核心逻辑, 而InvocationHandlerFactory其实就是创建InvocationHandler的工厂。


默认实现:

InvocationHandler的实现类FeignInvocationHandler。

最终会调用方法对应的MethodHandler的invoke方法。

Sentinel都实现了自己的InvocationHandler。

6.RequestInterceptor

是一个在发送请求前的一个拦截接口, 可以在发送Http请求之前再对Http请求的内容进行修改。如我们可以设置一些接口需要的公共参数, 授权token等。
java
@Component
public class TokenRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
template.header("token", "token值");
}
}
7.Retryer

是一个重试的组件。默认实现:

默认的重试机制次数为5次。
SpringCloud的默认实现是:

所以SpringCloud下默认是不会进行重试。
8.总结

还有一些组件: 日志级别Logger.Level, 日志输出Logger。