spring boot feign - 靜態(tài)主線(xiàn)

本篇主要分析open feign client組件。

OpenFeign是微服務(wù)(Eureka Client)之間進(jìn)行HTTP請(qǐng)求調(diào)用的組件。不適用于外部和服務(wù)之間的調(diào)用。

分析OpenFeign有兩條主線(xiàn),一靜一動(dòng)。靜態(tài)主線(xiàn),即OpenFeign配置加載,F(xiàn)eignClient初始化等;動(dòng)態(tài)主線(xiàn),即http調(diào)用。靜態(tài)主線(xiàn)是動(dòng)態(tài)主線(xiàn)的根基。
本文分析靜態(tài)主線(xiàn),從@EnableFeignClients注解——>BeanDefinition——>實(shí)例初始化

BeanDefinition

要分析feign,入手點(diǎn)肯定是@EnableFeignClients注解了。因?yàn)檫@是使用在Application上的,是所有feign的起點(diǎn)。下面是EnableFeignClients .java的源碼:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//FeignClientsRegistrar是ImportBeanDefinitionRegistrar的子類(lèi),用來(lái)處理@FeignClient注解
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
    /**
     * basePackages()屬性的別名
     */
    String[] value() default {};

    /**
     * 掃描基本包的注解組件,允許string類(lèi)型
     * @return 基本包名數(shù)組
     */
    String[] basePackages() default {};

    /**
     * 和上面的basePackages()一樣,只允許Class類(lèi)型
     * @return 基本類(lèi)名數(shù)組
     */
    Class<?>[] basePackageClasses() default {};

    /**
     * 一個(gè)給所有feign client自定義的@Configuration,能夠包含@Bean的作用,例如feign.codec.Decoder,feign.codec.Encoder,feign.Contract。
     * 默認(rèn)為 FeignClientsConfiguration。
     */
    Class<?>[] defaultConfiguration() default {};

    /**
     * 所有帶@FeignClient注解的類(lèi)。如果不為空,關(guān)閉路徑掃描機(jī)制
     * @return
     */
    Class<?>[] clients() default {};
}

上面的代碼中,F(xiàn)eignClientsRegistrar是ImportBeanDefinitionRegistrar的子類(lèi),Spring用ImportBeanDefinitionRegistrar來(lái)動(dòng)態(tài)注冊(cè)BeanDefinition。而OpenFeign通過(guò)FeignClientsRegistrar來(lái)處理@FeignClient修飾的FeignClient接口類(lèi)。將這些接口類(lèi)的BeanDefinition注冊(cè)到Spring容器中,這樣就可以使用@Autowired等方式來(lái)裝載這些FeignClient接口類(lèi)的Bean實(shí)例。

注冊(cè)BeanDefinition

其中org.springframework.cloud.openfeign.FeignClientsRegistrar#registerBeanDefinitions方法是用來(lái)注冊(cè)BeanDefinition的。BeanDefinition通俗點(diǎn)來(lái)講,就是可以@Autowired來(lái)引用這個(gè)類(lèi)或接口。

@Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
         //注冊(cè)所有@EnableFeignClients提供的配置屬性中相關(guān)Bean實(shí)例
        registerDefaultConfiguration(metadata, registry);
        //掃描package,注冊(cè)帶@FeignClient接口類(lèi)的Bean信息
        registerFeignClients(metadata, registry);
    }

下面來(lái)看一下這兩個(gè)方法:

private void registerDefaultConfiguration(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
        Map<String, Object> defaultAttrs = metadata
                .getAnnotationAttributes(EnableFeignClients.class.getName(), true);
      //如果EnableFeignClients配置了defaultConfiguration,才會(huì)走這里。一般不進(jìn)行任何特殊配置,都是有的。如果沒(méi)有,會(huì)使用默認(rèn)的FeignConfiguration。
        if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
            String name;
            //是否是嵌套類(lèi)/內(nèi)部類(lèi)
            if (metadata.hasEnclosingClass()) {
                name = "default." + metadata.getEnclosingClassName();
            }
            else {
                name = "default." + metadata.getClassName();
            }
            registerClientConfiguration(registry, name,
                    defaultAttrs.get("defaultConfiguration"));
        }
    }

入?yún)etadata來(lái)源于Spring的importBeanDefinitionRegistrars(它是個(gè)Map)的value屬性,存放著所有的注解。這個(gè)方法在下面注冊(cè)到FeignClient時(shí)也會(huì)用到。

private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
            Object configuration) {
        //生成BeanDefinition
        BeanDefinitionBuilder builder = BeanDefinitionBuilder
                .genericBeanDefinition(FeignClientSpecification.class);
        builder.addConstructorArgValue(name);
        builder.addConstructorArgValue(configuration);
        //注冊(cè)到register
        registry.registerBeanDefinition(
                name + "." + FeignClientSpecification.class.getSimpleName(),
                builder.getBeanDefinition());
    }

其中BeanDefinitionRegistry是Spring框架中,用于動(dòng)態(tài)注冊(cè)BeanDefinition信息的接口,調(diào)用其registerBeanDefinition方法可以將BeanDefinition注冊(cè)到Spring容器中,其第一個(gè)屬性就是beanName,eg:default.com.example.feignclient.FeignClientApplication.FeignClientSpecification
FeignClientSpecification類(lèi)實(shí)現(xiàn)了NamedContextFactory.Specification接口,它是OpenFeign組件實(shí)例化的重要一環(huán),它持有自定義配置類(lèi)提供的組件實(shí)例,供OpenFeign使用。SpringCloud框架使用NamedContextFactory創(chuàng)建一系列的運(yùn)行上下文(ApplicationContext),來(lái)讓對(duì)應(yīng)的Specification在這些上下文中創(chuàng)建實(shí)例對(duì)象,使得各個(gè)上下文中的對(duì)象相互獨(dú)立。

下面是上面提及的注冊(cè)到register的部分代碼:

@Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
        //此處斷言入?yún)⒉荒転榭眨咽÷?        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
            //校驗(yàn)是否有方法覆蓋或者靜態(tài)工廠方法類(lèi)
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition oldBeanDefinition;

        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
        if (oldBeanDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                //此處為重復(fù)覆蓋,上面的標(biāo)志為false,此處拋錯(cuò)
            }
            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(oldBeanDefinition)) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                //... 省略日志輸出
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
                    //檢查工廠Bean是否已經(jīng)創(chuàng)建
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
            //將注冊(cè)的BeanDefinition放到beanDefinitionMap中,同時(shí)也放到beanDefinitionNames中
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                     //manualSingletonNames是手動(dòng)添加的類(lèi)的set集合
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }
          //如果oldBeanDefinition不為空,或者是單例類(lèi),重置beanDefinitionMap和BeanDefinitionNames
        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

注冊(cè)FeignClient

下面是注冊(cè)FeignClient:

public void registerFeignClients(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
            //掃描classpath下所有的@FeignClient注解的類(lèi)
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(this.resourceLoader);

        Set<String> basePackages;
        //獲取EnableFeignClients注解所有的屬性
        Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
        //新建注解過(guò)濾器
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
                FeignClient.class);
        final Class<?>[] clients = attrs == null ? null
                : (Class<?>[]) attrs.get("clients");
          //上面講到過(guò)這個(gè)屬性,如果為空,則掃描帶@FeignClient注解的類(lèi)
        if (clients == null || clients.length == 0) {
              //添加Filter,設(shè)置基本包路徑
            scanner.addIncludeFilter(annotationTypeFilter);
            basePackages = getBasePackages(metadata);
        }
        else {
            final Set<String> clientClasses = new HashSet<>();
            basePackages = new HashSet<>();
            for (Class<?> clazz : clients) {
                basePackages.add(ClassUtils.getPackageName(clazz));
                clientClasses.add(clazz.getCanonicalName());
            }
            AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
                @Override
                protected boolean match(ClassMetadata metadata) {
                    String cleaned = metadata.getClassName().replaceAll("\\$", ".");
                    return clientClasses.contains(cleaned);
                }
            };
            scanner.addIncludeFilter(
                    new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
        }
      //遍歷basePackages
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidateComponents = scanner
                    .findCandidateComponents(basePackage);
            for (BeanDefinition candidateComponent : candidateComponents) {
                if (candidateComponent instanceof AnnotatedBeanDefinition) {
                    // verify annotated class is an interface
                    AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                    
                  //獲取@FeignClient中的所有屬性
                    Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(
                                    FeignClient.class.getCanonicalName());
                       //獲取@FeignClient注解中的value屬性
                    String name = getClientName(attributes);
                    //注冊(cè)name到注冊(cè)表中
                    registerClientConfiguration(registry, name,
                            attributes.get("configuration"));
                    //注冊(cè)FeignClient
                    registerFeignClient(registry, annotationMetadata, attributes);
                }
            }
        }
    }

實(shí)例初始化

FeignClientFactoryBean是Spring實(shí)例化所有帶@FeignClient注解的類(lèi)的工廠類(lèi)。通過(guò)其getObject()來(lái)獲取Bean實(shí)例。其代碼如下所示:

@Override
    public Object getObject() throws Exception {
        FeignContext context = applicationContext.getBean(FeignContext.class);
        Feign.Builder builder = feign(context);
              //默認(rèn)的url為""
        if (!StringUtils.hasText(this.url)) {
            String url;
            if (!this.name.startsWith("http")) {
                url = "http://" + this.name;
            }
            else {
                url = this.name;
            }
            url += cleanPath();
            return loadBalance(builder, context, new HardCodedTarget<>(this.type,
                    this.name, url));
        }
        // ....下面測(cè)試沒(méi)有走到,暫且不表

在OpenFeign中,F(xiàn)eignContext繼承了NamedContextFactory,用于存儲(chǔ)各類(lèi)OpenFeign的組件實(shí)例。
下面說(shuō)一下loadBalance方法,它負(fù)責(zé)對(duì)HTTP請(qǐng)求組成等:

protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
            HardCodedTarget<T> target) {
        Client client = getOptional(context, Client.class);
        if (client != null) {
            builder.client(client);
            Targeter targeter = get(context, Targeter.class);
            return targeter.target(this, builder, context, target);
        }

        throw new IllegalStateException(
                "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
    }

此處的targeter為org.springframework.cloud.openfeign.HystrixTargeter,而此處的build為feign.Feign.Builder,處理邏輯在org.springframework.cloud.openfeign.HystrixTargeter#target中,如下:

if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
    return feign.target(target);
}

進(jìn)而進(jìn)入feign.Feign.Builder#target(feign.Target<T>)方法中:

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

下面是build方法:

public Feign build() {
      SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
          new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
                                               logLevel, decode404);
      ParseHandlersByName handlersByName =
          new ParseHandlersByName(contract, options, encoder, decoder,
                                  errorDecoder, synchronousMethodHandlerFactory);
      return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
    }

其中contract為org.springframework.cloud.openfeign.support.SpringMvcContract,其包含Decoder、Encoder、ErrorCoder,是對(duì)參數(shù)或請(qǐng)求體進(jìn)行編解碼。所有的請(qǐng)求,如果沒(méi)有指定,全部默認(rèn)為GET請(qǐng)求。
下面是feign.ReflectiveFeign#newInstance方法,該方法生成一個(gè)api綁定在target上,最后會(huì)存入緩存中:

 @Override
  public <T> T newInstance(Target<T> target) {
    //處理該類(lèi)中每一個(gè)方法,返回結(jié)果中key,模板
    Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
    Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
    List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();

    for (Method method : target.type().getMethods()) {
      if (method.getDeclaringClass() == Object.class) {
        continue;
      } else if(Util.isDefault(method)) {
        DefaultMethodHandler handler = new DefaultMethodHandler(method);
        defaultMethodHandlers.add(handler);
        methodToHandler.put(method, handler);
      } else {
        methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
      }
    }
      //動(dòng)態(tài)代理部分,該部分移到最后分析
  }

下面是feign.ReflectiveFeign.ParseHandlersByName#apply方法:

    public Map<String, MethodHandler> apply(Target key) {
      //獲取這個(gè)接口下所有的方法,key.type()即該接口
      List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
      Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
      for (MethodMetadata md : metadata) {
        BuildTemplateByResolvingArgs buildTemplate;
        if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
      //有表單且沒(méi)有body的模板
          buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder);
        } else if (md.bodyIndex() != null) {
        //有body的模板
          buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder);
        } else {
      //通用模板,一般是get用的
          buildTemplate = new BuildTemplateByResolvingArgs(md);
        }
        result.put(md.configKey(),
                   factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
      }
      return result;
    }

下面是feign.Contract.BaseContract#parseAndValidatateMetadata(java.lang.Class<?>)方法:

@Override
    public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {
      //檢查各種屬性...代碼略
      Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
       //遍歷所有方法
      for (Method method : targetType.getMethods()) {
      //確定該方法不是Object的方法,不是靜態(tài)或者default方法
        if (method.getDeclaringClass() == Object.class ||
            (method.getModifiers() & Modifier.STATIC) != 0 ||
            Util.isDefault(method)) {
          continue;
        }
        MethodMetadata metadata = parseAndValidateMetadata(targetType, method);
        checkState(!result.containsKey(metadata.configKey()), "Overrides unsupported: %s",
                   metadata.configKey());
        result.put(metadata.configKey(), metadata);
      }
      return new ArrayList<MethodMetadata>(result.values());
    }

下面是org.springframework.cloud.openfeign.support.SpringMvcContract#parseAndValidateMetadata方法:

@Override
    public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
        //將要轉(zhuǎn)譯的方法存儲(chǔ)起來(lái)
        this.processedMethods.put(Feign.configKey(targetType, method), method);
        MethodMetadata md = super.parseAndValidateMetadata(targetType, method);

        RequestMapping classAnnotation = findMergedAnnotation(targetType,
                RequestMapping.class);
        if (classAnnotation != null) {
            // produces - use from class annotation only if method has not specified this
            if (!md.template().headers().containsKey(ACCEPT)) {
                parseProduces(md, method, classAnnotation);
            }

            // consumes -- use from class annotation only if method has not specified this
            if (!md.template().headers().containsKey(CONTENT_TYPE)) {
                parseConsumes(md, method, classAnnotation);
            }

            // headers -- class annotation is inherited to methods, always write these if
            // present
            parseHeaders(md, method, classAnnotation);
        }
        return md;
    }

其中Feign.configKey(targetType, method)的值格式為UserClient#getSth(String),

下面是feign.Contract.BaseContract#parseAndValidateMetadata方法:

 protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
      MethodMetadata data = new MethodMetadata();
    //設(shè)置返回值
      data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
      //設(shè)置方法的key,格式為UserClient#getSth(String)
      data.configKey(Feign.configKey(targetType, method));

      if(targetType.getInterfaces().length == 1) {
        processAnnotationOnClass(data, targetType.getInterfaces()[0]);
      }
    //處理類(lèi)上的注解
      processAnnotationOnClass(data, targetType);


      for (Annotation methodAnnotation : method.getAnnotations()) {
    //處理方法上的注解
        processAnnotationOnMethod(data, methodAnnotation, method);
      }
      //檢查方法狀態(tài) 代碼略
      Class<?>[] parameterTypes = method.getParameterTypes();
      Type[] genericParameterTypes = method.getGenericParameterTypes();

      Annotation[][] parameterAnnotations = method.getParameterAnnotations();
      int count = parameterAnnotations.length;
      for (int i = 0; i < count; i++) {
        boolean isHttpAnnotation = false;
        if (parameterAnnotations[i] != null) {
          isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);
        }
        if (parameterTypes[i] == URI.class) {
          data.urlIndex(i);
        } else if (!isHttpAnnotation) {
          //檢查表單參數(shù)和body
          data.bodyIndex(i);
          data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i]));
        }
      }
    //檢查head和queries參數(shù)

      return data;
    }

處理類(lèi)上注解部分,期間會(huì)拆分合成注解,如GetMapping拆為RequestMapping(method=GET)。會(huì)使用Proxy.newProxyInstance動(dòng)態(tài)代理生成一個(gè)SynthesizedAnnotationInvocationHandler代理類(lèi),里面存儲(chǔ)著RequestMapping注解的所有鍵值對(duì)。并將類(lèi)上的路徑放置第0位,方便取。下面是org.springframework.cloud.openfeign.support.SpringMvcContract#processAnnotationOnClass代碼:

@Override
    protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
        if (clz.getInterfaces().length == 0) {
      //生成一個(gè)RequestMapping的代理類(lèi)
            RequestMapping classAnnotation = findMergedAnnotation(clz,RequestMapping.class);
            if (classAnnotation != null) {
                // 如果在類(lèi)上有指定path,則做預(yù)置前拼接,即沒(méi)有/加/
                if (classAnnotation.value().length > 0) {
                    String pathValue = emptyToNull(classAnnotation.value()[0]);
                    pathValue = resolve(pathValue);
                    if (!pathValue.startsWith("/")) {
                        pathValue = "/" + pathValue;
                    }
                    data.template().insert(0, pathValue);
                }
            }
        }
    }

處理方法上的注解,對(duì)于RequestMapping的處理和類(lèi)上是一樣的。但是在最后會(huì)根據(jù)head屬性轉(zhuǎn)換為head屬性,如produces會(huì)轉(zhuǎn)為acceptconsumes會(huì)轉(zhuǎn)為content-type,head上的其他屬性也會(huì)相應(yīng)的轉(zhuǎn)換過(guò)去。代碼為org.springframework.cloud.openfeign.support.SpringMvcContract#processAnnotationOnMethod

@Override
    protected void processAnnotationOnMethod(MethodMetadata data,
            Annotation methodAnnotation, Method method) {
        if (!RequestMapping.class.isInstance(methodAnnotation) && !methodAnnotation
                .annotationType().isAnnotationPresent(RequestMapping.class)) {
            return;
        }

        RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class);
        // HTTP Method,設(shè)定默認(rèn)為get
        RequestMethod[] methods = methodMapping.method();
        if (methods.length == 0) {
            methods = new RequestMethod[] { RequestMethod.GET };
        }
        checkOne(method, methods, "method");
        data.template().method(methods[0].name());

        // path
        checkAtMostOne(method, methodMapping.value(), "value");
        if (methodMapping.value().length > 0) {
            String pathValue = emptyToNull(methodMapping.value()[0]);
            if (pathValue != null) {
                pathValue = resolve(pathValue);
                // Append path from @RequestMapping if value is present on method
                if (!pathValue.startsWith("/")
                        && !data.template().toString().endsWith("/")) {
                    pathValue = "/" + pathValue;
                }
                data.template().append(pathValue);
            }
        }

        // produces
        parseProduces(data, method, methodMapping);

        // consumes
        parseConsumes(data, method, methodMapping);

        // headers
        parseHeaders(data, method, methodMapping);

        data.indexToExpander(new LinkedHashMap<Integer, Param.Expander>());
    }

在參數(shù)處理時(shí),會(huì)判斷參數(shù)是否在head、url、queries上,如果沒(méi)有,就加到formParams中。

feign.ReflectiveFeign#newInstance中動(dòng)態(tài)代理部分:

 //動(dòng)態(tài)代理部分
 //在create方法中,methodToHandler對(duì)應(yīng)dispatch。dispatch在最后進(jìn)行分析
    InvocationHandler handler = factory.create(target, methodToHandler);
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);
    //將所有的方法與模板的關(guān)系綁定代理類(lèi)上,在使用時(shí)直接從代理類(lèi)中拿
    for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
      defaultMethodHandler.bindTo(proxy);
    }
    return proxy;

下面是create方法,返回的是ReflectiveFeign.FeignInvocationHandler類(lèi)型:

static final class Default implements InvocationHandlerFactory {

    @Override
    public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
      return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
    }
  }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,570評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,505評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,017評(píng)論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,786評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,219評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,438評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,971評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,796評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,995評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,230評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,662評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,918評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,697評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,991評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容