Spring Cloud之Open Feign调用流程和源码分析(一)

 Open Feign整个核心的调用过程大致如下:

 Spring Cloud之Open Feign调用流程和源码分析(一)_第1张图片

 下面根据源码详细分析:

  1. @EnableFeignClients引入FeignClientsRegistrar类实现了ImportBeanDefinitionRegistrar接口用过registerBeanDefinitions方法向spring容器中注入FeignClientSpecification类(FeignClient需要的重试策略,超时策略,日志等配置,如果某个服务没有设置,则读取默认的配置)
// 通过开启feign注解引入FeignClientsRegistrar类
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FeignClientsRegistrar.class})
public @interface EnableFeignClients {
   //.....
}

 FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar类,重写registerBeanDefinitions方法可以自定义bean在spring中的注册:

//自定义注册bean到spring容器
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
//...
    //自定义实现注册bean
  public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        this.registerDefaultConfiguration(metadata, registry);
        this.registerFeignClients(metadata, registry);
    }

//扫描包所有加了@FeignClient的接口类,并将其注册到spring容器中。
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//...

        Iterator var17 = ((Set)basePackages).iterator();

        while(var17.hasNext()) {
            String basePackage = (String)var17.next();
            Set candidateComponents = scanner.findCandidateComponents(basePackage);
            Iterator var21 = candidateComponents.iterator();

            while(var21.hasNext()) {
                BeanDefinition candidateComponent = (BeanDefinition)var21.next();
                if (candidateComponent instanceof AnnotatedBeanDefinition) {
                    AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition)candidateComponent;
                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                    Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
                    Map attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
                    String name = this.getClientName(attributes);
                    this.registerClientConfiguration(registry, name, attributes.get("configuration"));
                    this.registerFeignClient(registry, annotationMetadata, attributes);
                }
            }
        }
}


}

2.接着上面的registerFeignClient()方法,成feign client bean的包装类FeignClientFactoryBean,并将@FeignClient注解的属性注册到bean中。注册的FeignClientFactoryBean,是一个包装了我们需要执行的rpc服务的请求的类、url、服务名称以及回调方法等。

//生成feign client bean的包装类FeignClientFactoryBean,并将@FeignClient注解的属性注册到bean中。
 private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map attributes) {
        String className = annotationMetadata.getClassName();
        BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
        this.validate(attributes);
        definition.addPropertyValue("url", this.getUrl(attributes));
        definition.addPropertyValue("path", this.getPath(attributes));
        String name = this.getName(attributes);
        definition.addPropertyValue("name", name);
        definition.addPropertyValue("type", className);
        definition.addPropertyValue("decode404", attributes.get("decode404"));
        definition.addPropertyValue("fallback", attributes.get("fallback"));
        definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
        definition.setAutowireMode(2);
        String alias = name + "FeignClient";
        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
        boolean primary = (Boolean)attributes.get("primary");
        beanDefinition.setPrimary(primary);
        String qualifier = this.getQualifier(attributes);
        if (StringUtils.hasText(qualifier)) {
            alias = qualifier;
        }

        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
    }

FeignClientFactoryBean类定义: 

private Class type;
private String name;
private String url;
private String path;
private boolean decode404;
private ApplicationContext applicationContext;
private Class fallback;
private Class fallbackFactory;

3.FeignClientFactoryBean实现了FactoryBean接口,在注解使用实例对象的时候会从spring容器中获取,获取方式就是调用FactoryBean的getObject()方法:

public interface FactoryBean {
    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class getObjectType();

    default boolean isSingleton() {
        return true;
    }
//获取代理对象
public Object getObject() throws Exception {
    FeignContext context = (FeignContext)this.applicationContext.getBean(FeignContext.class);
    Builder builder = this.feign(context);
    String url;
    //FeignClient不存在url的走负载均衡器
    if (!StringUtils.hasText(this.url)) {
        if (!this.name.startsWith("http")) {
            url = "http://" + this.name;
        } else {
            url = this.name;
        }

        url = url + this.cleanPath();
        return this.loadBalance(builder, context, new HardCodedTarget(this.type, this.name, url));

//负载均衡
protected  T loadBalance(Builder builder, FeignContext context, HardCodedTarget target) {
    Client client = (Client)this.getOptional(context, Client.class);
    if (client != null) {
        builder.client(client);
        Targeter targeter = (Targeter)this.get(context, Targeter.class);
        return targeter.target(this, builder, context, target);
//获取目标对象
public  T target(FeignClientFactoryBean factory, Builder feign, FeignContext context, HardCodedTarget target) {
    return feign.target(target);
}

public  T target(Target target) {
    return this.build().newInstance(target);
}

4.生成默认的处理方法FeignInvocationHandler实现了jdk自带的动态代理调用接口InvocationHandler,并且为目标类生成代理类;

    public  T newInstance(Target target) {
 //InvocationHandler最终执行的方法
Map nameToHandler = this.targetToHandlersByName.apply(target);
    //...
       //创建FeignInvocationHandler包装类,该类实现了jdk动态代理默认需要实现的接口InvocationHandler,后续通过invoke()方法转发到nameToHandler中处理
        InvocationHandler handler = this.factory.create(target, methodToHandler);
        //创建动态代理对象
        T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);
        Iterator var12 = defaultMethodHandlers.iterator();
}

//创建FeignInvocationHandler包装类Target(class、name、url),dispatchd请求分发
  public InvocationHandler create(Target target, Map dispatch) {
            return new FeignInvocationHandler(target, dispatch);
        }

public InvocationHandler create(Target target, Map dispatch) {
            return new FeignInvocationHandler(target, dispatch);
        }

    //获取SynchronousMethodHandler类
   public Map apply(Target key) {
                   for(Iterator var4 = metadata.iterator(); var4.hasNext(); result.put(md.configKey(), this.factory.create(key, md, (Factory)buildTemplate, this.options, this.decoder, this.errorDecoder))) {

}
//handler重写后的invoke()方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (!"equals".equals(method.getName())) {
        if ("hashCode".equals(method.getName())) {
            return this.hashCode();
        } else {
            return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args);
        }

 public MethodHandler create(Target target, MethodMetadata md, feign.RequestTemplate.Factory buildTemplateFromArgs, Options options, Decoder decoder, ErrorDecoder errorDecoder) {
            return new SynchronousMethodHandler(target, this.client, this.retryer, this.requestInterceptors, this.logger, this.logLevel, md, buildTemplateFromArgs, options, decoder, errorDecoder, this.decode404);
        }


//Target的属性
public interface Target {
    Class type();

    String name();

    String url();
}

Spring Cloud之Open Feign调用流程和源码分析(一)_第2张图片

 5.然后走SynchronousMethodHandler的invoke()方法进行真正的rpc调用返回结果。

Spring Cloud之Open Feign调用流程和源码分析(一)_第3张图片

//SynchronousMethodHandler调用invoke()方法,开始执行请求
  public Object invoke(Object[] argv) throws Throwable {
        RequestTemplate template = this.buildTemplateFromArgs.create(argv);
        Retryer retryer = this.retryer.clone();

        while(true) {
            try {
                return this.executeAndDecode(template);
            } catch (RetryableException var5) {
                retryer.continueOrPropagate(var5);
                if (this.logLevel != Level.NONE) {
                    this.logger.logRetry(this.metadata.configKey(), this.logLevel);
                }
            }
        }
    }

然后走到client真正开始执行请求的地方: 

Spring Cloud之Open Feign调用流程和源码分析(一)_第4张图片

 6.默认的client是LoadBalancerFeignClient,采用负载均衡策略的方式执行我们请求:

Spring Cloud之Open Feign调用流程和源码分析(一)_第5张图片

下一篇将进一步分析LoadBalancer负载均衡器,讲述lb-ribbon涉及的组件和底层工作原理。

你可能感兴趣的:(源码解读,java,spring,spring,boot,spring,cloud,spring,cloud,alibaba)