回顾
在 Feign 如何进行服务间调用 一文中,提到了Feign 自动配置类 FeignAutoConfiguration。
Feign 对象进行实例化的时候会调用 Targeter targeter = get(context, Targeter.class); 来进行获取。
Targeter 有两种实现: DefaultTargeter 和 HystrixTargeter。
Feign 如何进行服务间调用 中我们以 DefaultTargeter 进行展开。而在 Feign Hystrix Support 讨论中,以 HystrixTargeter 展开。
Feign Hystrix Support
Spring Cloud 官网相关案例信息
回顾熟悉一下 Feign 的使用

源码分析 HystrixTargeter 配置下的 Feign Client 代理对象
聚焦 Feign 自动配置类 FeignAutoConfiguration

从自动配置类 FeignAutoConfiguration 中,我们可以很直观的看到,当我们在依赖中引入 feign-hystrix 和 hystrix 时,Feign 会采用 HystrixTargeter作为其 Targeter 的实现类。
Feign Hystrix 功能支持,由 HystrixTargeter#target 实例化对象时生成一系列HystrixCommand 相关配置来实现。
提示:Feign Client 的加载可以分为三步。HystrixTargeter#target 的调用属于第二步:Feign Client 实例化代理对象。
聚焦 HystrixTargeter#target

HystrixTargeter#target 逻辑
1、如果项目中没有引入 feign-hystrix 和 hystrix 依赖 HystrixTargeter 和 DefaultTargeter 返回的 Target 对象信息是一致的。
2、存在feign-hystrix 相关依赖时,Feign.Builder 强制转为 HystrixFeign.Builder。
3、尝试获取 hystrix 配置 SetterFactory,如果存在进行属性设置
4、尝试获取 Feign Client 对应的hystrix fallback 类,如果存在,调用 HystrixTargeter#targetWithFallback 返回实例化代理对象。
5、hystrix fallback 不存在,尝试获取 hystrix fallbackFactory 类,如果存在 调用 HystrixTargeter#targetWithFallbackFactory 返回实例化代理对象。
6、如果 fallback 和 fallbackFactory 都不存在,直接调用 返回实例化代理对象。返回的 Target 对象信息和 DefaultTargeter 一致。
也就是说:在依赖中引入 Hystrix 相关依赖的同时, Feign Client 中也需要定义 Hystrix 熔断信息的类 Fallback 或者 FallbackFactory ,Feign 才会生成支持 Hystrix 功能的 Target 对象。
假设此时有一个 Feign Client ,定义了 Hystrix 熔断信息类:fallbackFactory 。以此为前提来进行源码追踪。
聚焦HystrixTargeter#targetWithFallbackFactory

关注代码中的 HystrixTargeter#getFromContext 方法,该方法主要是根据相关信息,从 Spring 容器中获取 FallbackFacotry 实例化对象。
之后代码调用 HystrixFeign.Builder#target() 方法。
聚焦HystrixFeign.Builder#target()

HystrixFeign.Builder#target() 主要是两个执行操作:
build 构建 HystrixInvocationHandler 对象。
DefaultTargeter 调用 build() 默认构造对象是 ReflectiveFeign.FeignInvocationHandler进行代理对象的实例化操作。
HystrixTargeter 实例化对象和 DefaultTargeter 都是调用的 ReflectiveFeign#newInstance
虽说 HystrixTargeter 和 DefaultTargeter 实例化代理对象调用的方法相同得到的实例对象都是 HardCodedTarget 但是对应生成的代理对象是不一样的。
为了验证我的观点,来看看 ReflectiveFeign#newInstance 部分代码

通过代码能够知道被代理对象 HardCodedTarget 的代理类 接口为 InvocationHandler。
而HystrixTargeter 和 DefaultTargeter 对应的 InvocationHandler 实现是不同的。
| Targeter | InvocationHandler |
|---|---|
| HystrixTargeter | HystrixInvocationHandler |
| DefaultTargeter | ReflectiveFeign.FeignInvocationHandler |
Build不同加上代理对象的不同,使得 HystrixTargeter 和 DefaultTargeter 生成不同的代理对象信息。
下面我们来简单的对比下 HystrixTargeter 和 DefaultTargeter 配置下生成的代理类的差异:

对比 HystrixTargeter 和 DefaultTargeter 配置下生成的代理类的差异,HystrixTargeter 相比 DefaultTargeter 多了 fallback 相关方法。
从简单的代码结构看不出具体的差异信息,我们再来看看 HystrixTargeter 与 DefaultTargeter 进行代理调用时的差异。
调用 HystrixTargeter 配置生成的代理对象
在 HystrixTargeter 配置下发起 Feign Client 服务调用是,方法会进入到 HystrixInvocationHandler 代理对象中。
聚焦 HystrixInvocationHandler#invoke

看到这里,整个执行就很直观了。 HystrixInvocationHandler 执行 Feign Client 的服务调用和 ReflectiveFeign.FeignInvocationHandler 基本一致,区别在于 HystrixInvocationHandler 在方法执行外层包裹了 HystrixCommand ,为 Feign 调用提供了 Hystrix 能力。
总结
Feign 提供 Hystrix 功能 对比 Feign Default 功能。
| 代理对象 | Targeter实现 | |
|---|---|---|
| Feign Hystrix Support | HystrixInvocationHandler | HystrixTargeter |
| Feign Default | ReflectiveFeign.FeignInvocationHandler | DefaultTargeter |
在执行 Feign Client 调用时,HystrixInvocationHandler#invoke 对比 ReflectiveFeign.FeignInvocationHandler#invoke 最大区别在于 HystrixInvocationHandler#invoke 在调用 Feign Client 时,会对请求封装一层 HystrixCommand,对 Feign 调用进行增强,提供 Hystrix 功能。
-- END --

长按二维码 ▲
关注 [ WTF名字好难取 ] 公众号
往期回顾
Spring Cloud Feign【源码篇】Feign 如何进行服务间请求调用
Spring Cloud Hystrix【应用篇】 Hystrix Dashboard
Nginx【应用篇】记一次Nginx问题 SSL_SHUTDOWN





