Spring Cloudspring cloud

Spring Cloud Feign 分析(五)之FeignCl

2021-03-26  本文已影响0人  Blog

使用过FeignClient的同学可能都知道,FeignClient在使用的过程中会生成一个代理类,所有操作都是由代理类去完成,这个的确是这样的,但是当有人问这个代理类是如何生成的?这个代理类做了哪些事情呢?不熟悉代理生成过程的我们可能就会不知如何回答,所以本节的我们使命就是分析FeignClient代理生成过程!


FeignClientFactoryBean

Spring Cloud Feign 分析(一)之FeignClient注册过程中讲解过FeignClientsRegistrar#registerFeignClients这个方法中return factoryBean.getObject();会返回一个代理对象,但是并没有深入讲解,特此放到本节进行统一讲解!

public class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
        ApplicationContextAware, BeanFactoryAware {
    ......
    //创建HystrixFeign.builder
    protected Feign.Builder feign(FeignContext context) {
        //创建DefaultFeignLoggerFactory
        FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
        //默认返回Slf4jLogger
        Logger logger = loggerFactory.create(type);
        //获取HystrixFeign.Builder
        Feign.Builder builder = get(context, Feign.Builder.class)
                 //默认Slf4jLogger
                .logger(logger)
                //默认SpringEncoder
                .encoder(get(context, Encoder.class))
                //默认SpringDecoder
                .decoder(get(context, Decoder.class))
                //默认SpringMvcContract
                .contract(get(context, Contract.class));
        //设置Feign.Builder 的其他配置,如ErrorDecoder、Retryer等配置
        configureFeign(context, builder);
        //扩展给外部使用者,外部使用者可以给Feign.Builder设置其他参数
        applyBuildCustomizers(context, builder);
        //返回Feign.Builder => HystrixFeign.Builder
        return builder;
    }
    //获取代理对象
    @Override
    public Object getObject() {
        return getTarget();
    }
    //代理对象实现过程,根据url参数区分使用哪一种策略
    <T> T getTarget() {
        //获取FeignContext工厂类
        FeignContext context = beanFactory != null
                ? beanFactory.getBean(FeignContext.class)
                : applicationContext.getBean(FeignContext.class);
        //获取HystrixFeign.builder()
        Feign.Builder builder = feign(context);
        //如果@FeignClient中为配置url,则使用如下方式,负载均衡方式
        if (!StringUtils.hasText(url)) {
            if (!name.startsWith("http")) {
                url = "http://" + name;
            }
            else {
                url = name;
            }
            url += cleanPath();
            //设置client为LoadBalancerFeignClient,具备负载均衡
            //返回HystrixTargeter.target中返回的代理类
            return (T) loadBalance(builder, context,
                    new HardCodedTarget<>(type, name, url));
        }
        //@FeignClient中配置的url,使用如下方式,以下方式均为不使用负载均衡的方式
        if (StringUtils.hasText(url) && !url.startsWith("http")) {
            url = "http://" + url;
        }
        String url = this.url + cleanPath();
        Client client = getOptional(context, Client.class);
        if (client != null) {
            if (client instanceof LoadBalancerFeignClient) {
                client = ((LoadBalancerFeignClient) client).getDelegate();
            }
            if (client instanceof FeignBlockingLoadBalancerClient) {
                client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
            }
            //返回的client为Client.Default,不具备负载均衡作用
            builder.client(client);
        }
        //返回HystrixTargeter.target中返回的代理类
        Targeter targeter = get(context, Targeter.class);
        return (T) targeter.target(this, builder, context,
                new HardCodedTarget<>(type, name, url));
    }
}

经过我们不懈努力,FeignClientFactoryBean这个代理工厂类中代码片段已经标上了注释信息,为了便于我们更好的理解,我们汇总一下执行步骤:

  1. 获取FeignContext这个Feign工厂类上下文,用于从中获取所需的Bean
  2. 从FeignContext上下文中获取HystrixFeign.builder
  3. 设置HystrixFeign.builder的logger(Slf4jLogger)、encoder(默认SpringEncoder)、decoder(默认SpringDecoder)、contract(默认SpringMvcContract),如果有自定义实现则使用,否则使用默认值
  4. 设置Feign.Builder 的其他配置,如ErrorDecoder、Retryer等配置
  5. 将HystrixFeign.builder外抛给外部用于扩展,使用者可以设置相关参数
  6. 根据@FeignClient中配置是否配置了url参数,为Feign.Builder设置client参数,client分为负载均衡方式与非负载均衡方式
  7. 返回HystrixTargeter.target中返回的代理类

HystrixTargeter

class HystrixTargeter implements Targeter {

    @Override
    public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
            FeignContext context, Target.HardCodedTarget<T> target) {
        //是否为Feign.Builder 类型,若不是则直接创建代理对象并执行
        if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
            return feign.target(target);
        }
        //转换为HystrixFeign.Builder类型
        feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
        //获取上下文id,其实就是获取的@FeignClient注解的name、value属性值
        String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName()
                : factory.getContextId();
        //获取SetterFactory,主要是HystrixCommand的groupKey、commandKey参数,默认setterFactory为空
        SetterFactory setterFactory = getOptional(name, context, SetterFactory.class);
        //setterFactory不为空就设置
        if (setterFactory != null) {
            builder.setterFactory(setterFactory);
        }
        //获取降级方法,默认为void初始状态
        Class<?> fallback = factory.getFallback();
        if (fallback != void.class) {
            //如果有设置了fallback,则使用
            return targetWithFallback(name, context, target, builder, fallback);
        }
        //获取降级工厂类FallbackFactory,默认为void初始状态
        Class<?> fallbackFactory = factory.getFallbackFactory();
        if (fallbackFactory != void.class) {
            return targetWithFallbackFactory(name, context, target, builder,
                    fallbackFactory);
        }
        //调用HystrixFeign#build()
        return feign.target(target);
    }
    //具有FallbackFactory的目标执行类
    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);
        //返回具有FallbackFactory的代理实例
        return builder.target(target, fallbackFactory);
    }
    //具有Fallback的目标执行类
    private <T> T targetWithFallback(String feignClientName, FeignContext context,
            Target.HardCodedTarget<T> target, HystrixFeign.Builder builder,
            Class<?> fallback) {
        //获取降级实例
        T fallbackInstance = getFromContext("fallback", feignClientName, context,
                fallback, target.type());
        //返回具有fallback的代理实例
        return builder.target(target, fallbackInstance);
    }
    //返回指定类型的实例
    private <T> T getFromContext(String fallbackMechanism, String feignClientName,
            FeignContext context, Class<?> beanType, Class<T> targetType) {
        ......
        return (T) fallbackInstance;
    }
    //根据@FeignClient注解的name、value属性值获取对应beanType实例
    private <T> T getOptional(String feignClientName, FeignContext context,
            Class<T> beanType) {
        return context.getInstance(feignClientName, beanType);
    }
}

通过上文中FeignClientFactoryBean的步骤中可知,在HystrixTargeter#target这个方法中最后一段return feign.target(target);经过的步骤如下:

  1. 调用Feign#Builder#target(Target<T> target)
  2. 调用HystrixFeign#build()
  3. 调用HystrixFeign#build(final FallbackFactory<?> nullableFallbackFactory)
  4. 调用Feign#build()
  5. 调用ReflectiveFeign#newInstance(Target<T> target)
  6. 返回代理对象proxy

HystrixTargeter汇总的步骤大约是6个步骤,但是这6个步骤因为存在来回调用,所以在下文里会重点分析每个步骤具体做了哪些事情,这样才有利于我们清楚生成代理对象的整个过程!


Feign#Builder

public abstract class Feign {
  ......
  //会调用到ReflectiveFeign#newInstance(Target<T> target)
  public abstract <T> T newInstance(Target<T> target);
  //返回代理对象
  public static class Builder {
    public <T> T target(Target<T> target) {
      //build()这个方法会调用到HystrixFeign#build()
      return build().newInstance(target);
    }
    //基础build,Capability可以理解为增强功能,通过增强,可以对Client这些配置进行额外操作,默认不会增强,返回原始值
    public Feign build() {
      //默认返回原始Client,以下都是未增强的,都是原始值
      Client client = Capability.enrich(this.client, capabilities);
      Retryer retryer = Capability.enrich(this.retryer, capabilities);
      List<RequestInterceptor> requestInterceptors = this.requestInterceptors.stream()
          .map(ri -> Capability.enrich(ri, capabilities))
          .collect(Collectors.toList());
      Logger logger = Capability.enrich(this.logger, capabilities);
      Contract contract = Capability.enrich(this.contract, capabilities);
      Options options = Capability.enrich(this.options, capabilities);
      Encoder encoder = Capability.enrich(this.encoder, capabilities);
      Decoder decoder = Capability.enrich(this.decoder, capabilities);
      //InvocationHandlerFactory工厂类,负责创建InvocationHandler代理类的执行方法
      InvocationHandlerFactory invocationHandlerFactory =
          Capability.enrich(this.invocationHandlerFactory, capabilities);
      QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
      //负责创建SynchronousMethodHandler方法执行Handler的工厂类
      SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
          new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
              logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
      //用于解析接口得到方法名称和对应的MethodHandler
      ParseHandlersByName handlersByName =
          new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
              errorDecoder, synchronousMethodHandlerFactory);
      //返回代理实例
      return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
    }
  }
  ......
}

在调用target(Target<T> target)方法之后,因为HystrixFeign#Builder继承Feign.Builder,所以默认会执行下文中的HystrixFeign#build方法,然后HystrixFeign#build()方法中会设置Hystrix相关的配置,在Feign#build()这个方法中会通过增强Capability接口进行获取相关的配置,可以对Client这些配置进行额外操作,默认不会增强,返回原始值,最终将相关的参数设置给ReflectiveFeign并返回最终的代理对象!


HystrixFeign#build

public final class HystrixFeign {
  public static final class Builder extends Feign.Builder {
    ......
    @Override
    public Feign build() {
      return build(null);
    }
    //配置组件具备hystrix功能
    Feign build(final FallbackFactory<?> nullableFallbackFactory) {
      //设置代理对象的InvocationHandler,会将执行的方法HystrixCommand.execute(),这样就具备了Hystrix的熔断能力
      super.invocationHandlerFactory(new InvocationHandlerFactory() {
        @Override
        public InvocationHandler create(Target target,
                                        Map<Method, MethodHandler> dispatch) {
          //HystrixInvocationHandler实现了InvocationHandler,会在ReflectiveFeign#newInstance中设置到代理类中
          return new HystrixInvocationHandler(target, dispatch, setterFactory,
              nullableFallbackFactory);
        }
      });
      //将我们原本的contract协议具备Hystrix能力
      super.contract(new HystrixDelegatingContract(contract));
      //调用父类Feign#Builder#build()
      return super.build();
    }
    ......
  }
}

HystrixFeign#build这个方法就比较直观,就是配置组件具备hystrix功能,通过创建具备Hystrix熔断功能的InvocationHandler拦截器,然后内部通过HystrixCommand.execute()来触发请求,contract也包装给HystrixDelegatingContract让其具备Hystrix处理能力!


ReflectiveFeign#newInstance

public class ReflectiveFeign extends Feign {
  ......
  @Override
  public <T> T newInstance(Target<T> target) {
    //ParseHandlerByName解析接口得到方法名称和对应的MethodHandler
    Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
    //方法和对应的MethodHandler
    Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
    //默认方法集合
    List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
    //反射获取@FeignClient接口声明方法
    for (Method method : target.type().getMethods()) {
      if (method.getDeclaringClass() == Object.class) {
        continue;
      } else if (Util.isDefault(method)) {
        //Default methods are public non-abstract, non-synthetic, and non-static instance methods
        //正常情况下@FeignClient接口不会走这里
        DefaultMethodHandler handler = new DefaultMethodHandler(method);
        defaultMethodHandlers.add(handler);
        methodToHandler.put(method, handler);
      } else {
        //@FeignClient接口方法放入到methodToHandler中
        methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
      }
    }
    //通过invocationHandlerFactory创建HystrixInvocationHandler
    InvocationHandler handler = factory.create(target, methodToHandler);
    //JDK动态代理创建代理对象并设置代理类的InvocationHandler,这样就可以通过Hystrix发起请求
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
        new Class<?>[] {target.type()}, handler);
    //将接口的默认方法绑定到生成的代理对象
    for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
      defaultMethodHandler.bindTo(proxy);
    }
    return proxy;
  }
  ......
}

ReflectiveFeign#newInstance这个方法中,我们可以看到其实就是在解析target这个对象,因为这个target是由@FeignClient注解包装而来的,所以大致步骤为:

  1. 通过ParseHandlerByName解析接口得到方法名称和对应的MethodHandler,其中Key => Class#Function(String,String,String),Class即为定义了@FeignClient注解的接口类名,Function则为该接口中的方法名
  2. 反射获取@FeignClient接口声明方法,将其加入methodToHandler这个方法和对应的MethodHandler
  3. 通过invocationHandlerFactory创建HystrixInvocationHandler
  4. JDK动态代理创建代理对象并设置代理类的InvocationHandler,这样就可以通过Hystrix发起请求
  5. 将接口的默认方法绑定到生成的代理对象 => 正常情况不会有
  6. 返回代理对象proxy

生成代理对象这个过程非常的复杂,我也只是总结了自己认为比较重要的部分,如果有兴趣可以在看看ParseHandlerByName这个解析接口的过程,相信对我们的代码设计能力有所帮助,后续的章节会继续讲解@FeignClient的调用过程,因为知道整个调用过程对我们排查问题非常有用!

上一篇下一篇

猜你喜欢

热点阅读