写于:2019-06-25 22:52:37
相关版本:Spring Boot 2.1.5.RELEASE 、Spring Cloud Greenwich.SR
一、回顾
在 《Feign 如何进行服务间调用》 一文中,提到了Feign 自动配置类 FeignAutoConfiguration。
在之前提到,Feign 对象进行实例化的时候会调用 Targeter targeter = get(context, Targeter.class); 来进行获取。
Targeter 有两种实现: DefaultTargeter 和 HystrixTargeter。
《Feign 如何进行服务间调用》 中以 DefaultTargeter 进行展开。
在 Feign Hystrix Support 中,通过查看自动配置类 FeignAutoConfiguration 信息,在有 Hystrix 相关依赖情况下,Feign Targeter 的实现为 HystrixTargeter。
二、Feign Hystrix Support
Spring Cloud 官网相关案例信息
三、源码分析 HystrixTargeter 配置下的 Feign Client 代理对象
聚焦 Feign 自动配置类 FeignAutoConfiguration
public class FeignAutoConfiguration {@Configuration@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")protected static class DefaultFeignTargeterConfiguration {@Bean@ConditionalOnMissingBeanpublic Targeter feignTargeter() {return new DefaultTargeter();}}@Configuration@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")protected static class HystrixFeignTargeterConfiguration {@Bean@ConditionalOnMissingBeanpublic Targeter feignTargeter() {return new HystrixTargeter();}}}
从自动配置类 FeignAutoConfiguration 中,我们可以很直观的看到,当我们在依赖中引入 feign-hystrix 和 hystrix 时,Feign 会采用 HystrixTargeter作为其 Targeter 的实现类。
Feign Hystrix 功能支持,由 HystrixTargeter#target 实例化对象时生成一系列HystrixCommand 相关配置。
小贴士:Feign Client 的加载可以分为三步。HystrixTargeter#target 的调用属于第二步:Feign Client 实例化代理对象。
聚焦 HystrixTargeter#target
class HystrixTargeter implements Targeter {@Overridepublic <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,FeignContext context, Target.HardCodedTarget<T> target) {// 1、判定是否引入依赖 feign-hystirxif (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {return feign.target(target);}// 2、将 Feign.Builder 强制转化为 HystrixFeign.Builderfeign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;// 3、获取 SetterFacotry,如果有,设置HystrixFeign.Builder 属性SetterFactory setterFactory = getOptional(factory.getName(), context,SetterFactory.class);if (setterFactory != null) {builder.setterFactory(setterFactory);}// 4、获取 fallback 方法,如果有,返回构造的 TargetClass<?> fallback = factory.getFallback();if (fallback != void.class) {return targetWithFallback(factory.getName(), context, target, builder,fallback);}//5、获取 FallbackFactory ,如果有,返回构造的 TargetClass<?> fallbackFactory = factory.getFallbackFactory();if (fallbackFactory != void.class) {return targetWithFallbackFactory(factory.getName(), context, target, builder,fallbackFactory);}return feign.target(target);}}
HystrixTargeter#target 逻辑
1、如果项目中没有引入 feign-hystrix 和 hystrix 依赖 HystrixTargeter 和 DefaultTargeter 返回的 Target 对象信息是一致的。
2、存在feign-hystrix 相关依赖时,Feign.Builder 强制转为 HystrixFeign.Builder。
3、尝试获取 SetterFactory,如果存在进行属性设置
4、尝试获取 Feign Client 对应的 fallback 类,如果存在,调用 HystrixTargeter#targetWithFallback 返回实例化代理对象。
5、fallback 不存在,尝试获取 fallbackFactory 类,如果存在 调用 HystrixTargeter#targetWithFallbackFactory 返回实例化代理对象。
6、如果 fallback 和 fallbackFactory 都不存在,直接调用 返回实例化代理对象。返回的 Target 对象信息想和 DefaultTargeter 一致。
也就是说:在 Feign Client 中只有定义了 Hystrix 熔断信息的类 Fallback 或者 FallbackFactory ,Feign 才会支持 Hystrix 功能。
假设此时有一个 Feign Client ,定义了 Hystrix 熔断信息类:fallbackFactory 。以此来进行源码追踪。
聚焦HystrixTargeter#targetWithFallbackFactory
class HystrixTargeter implements Targeter {private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,Target.HardCodedTarget<T> target, HystrixFeign.Builder builder,Class<?> fallbackFactoryClass) {FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass,FallbackFactory.class);return builder.target(target, fallbackFactory);}}
代码中关注 HystrixTargeter#getFromContext 方法,该方法主要是根据相关信息,从 Spring 容器中获取 FallbackFacotry 实例化对象。
之后代码调用 HystrixFeign.Builder#target() 方法。
聚焦HystrixFeign.Builder#target()
public final class HystrixFeign {public static final class Builder extends Feign.Builder {public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {return build(fallbackFactory).newInstance(target);}/** Configures components needed for hystrix integration. */Feign build(final FallbackFactory<?> nullableFallbackFactory) {super.invocationHandlerFactory(new InvocationHandlerFactory() {@Overridepublic InvocationHandler create(Target target,Map<Method, MethodHandler> dispatch) {return new HystrixInvocationHandler(target, dispatch, setterFactory,nullableFallbackFactory);}});super.contract(new HystrixDelegatingContract(contract));return super.build();}}}
HystrixFeign.Builder#target() 主要是两个执行操作:
- build 构建 HystrixInvocationHandler 对象。
DefaultTargeter 调用 build() 默认构造对象是 ReflectiveFeign.FeignInvocationHandler - 进行代理对象的实例化操作。
HystrixTargeter 实例化对象和 DefaultTargeter 都是调用的 ReflectiveFeign#newInstance
虽说 HystrixTargeter 和 DefaultTargeter 实例化代理对象调用的方法相同得到的实例对象都是 HardCodedTarget 但是对应生成的代理对象是不一样的。
验证我的观点,来看看 ReflectiveFeign#newInstance 部分代码,
public class ReflectiveFeign extends Feign {private final InvocationHandlerFactory factory;@Overridepublic <T> T newInstance(Target<T> target) {......InvocationHandler handler = factory.create(target, methodToHandler);T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[] {target.type()}, handler);return proxy;}}
通过代码,能够知道被代理对象 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
final class HystrixInvocationHandler implements InvocationHandler {@Overridepublic Object invoke(final Object proxy, final Method method, final Object[] args)throws Throwable {HystrixCommand<Object> hystrixCommand =new HystrixCommand<Object>(setterMethodMap.get(method)) {@Overrideprotected Object run() throws Exception {try {return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);} catch (Exception e) {throw e;} catch (Throwable t) {throw (Error) t;}}@Overrideprotected Object getFallback() {......}};......return hystrixCommand.execute();}}
看到这里,整个执行就很直观了。 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 功能。
