1、概述

* 代码架构

  - 顶级接口Client表示一个通信客户端,只有一个execute方法,其实现类有多种,有提供最基本通信功能的ApacheClient、OKhttpClient、

- 还有其他装饰过的实现类,如提供负载均衡的通信客户端LoadBlancerFeignClient,对基本Client进行再次封装,负载功能由FeignLoadBlancer提供

  其核心的选择服务实例的还能就是由ILoadBalancer总控组件提供,这一点和Spring Ribbon是一样的

* OpenFeign只是对 HTTP 调用组件进行了易用性封装,底层还是使用我们常见的 OkHttp、HttpClient 、ILoadBalancer总控负载组件等组件

* OpenFeign的目标之一就让这些 HTTP 客户端更好用,使用方式更统一,更像RPC。

2@EnableFeignClients注解开启

@EnableFeignClients("com.kaka")
@SpringBootApplication
public class ConsumerApplication{
    public static void main(String[] args){
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {

   //@FeignClient注解的接口路径指定
   String[] value() default {};
   String[] basePackages() default {};
   Class<?>[] basePackageClasses() default {};

Class<?>[] clients() default {};

   //全局默认配置类
   Class<?>[] defaultConfiguration() default {};

}

2.1、注册(全局/特定)FeignClientSpecification类bean定义

class FeignClientSpecification implements NamedContextFactory.Specification {
        private String name;
        private Class<?>[] configuration;
    }

主要流程

* 注册默认的FeignClient配置类定义——@EnableFeignClients注解指定

  - 获取@EnableFeignClients主注解上defaultConfiguration指定的类,注册bean定义到容器中

创建bean定义,bean名称为default + defaultConfiguration类名 + FeignClientSpecification,类型为FeignClientSpecification,构造参数为defaultConfiguration指定的类。

  - FeignClientSpecification中对应name属性值为default + defaultConfiguration类名

@EnableFeignClients(defaultConfiguration = xxx.class)
    public class xxx { }

* 注册特定客户端的配置类定义,注册到容器中——@FeignClient注解指定

- 创建bean定义,名称取值(为空依次取contextId\value\name\serviceId属性值)+FeignClientSpecification,类型为FeignClientSpecification,

- 构造参数为configuration属性指定的类(可能为null);name属性为取值(为空依次取contextId\value\name\serviceId属性值)

@FeignClient(value = "openFeign-provider",configuration = xx.class)
  public interface OpenFeignService {}

2.2、注册FeignClient接口的bean定义

* 获取扫描的范围,接着进行注册

- 如果@EnableFeignClients注解的clients为空

- 获取@EnableFeignClients主键的value、basePackages、basePackageClasses属性指定的包路

如果都为空就默认使用标志此注解的类本身路径,扫描添加了@FeignClient注解的接口

- 如果@EnableFeignClients注解的clients不为空,则扫描指定客户端类

* 向容器创建注册@FeignClient接口对应的使用BeanDefinition,使用FactoryBean工厂bean的形式,将Bean的具体生成过程收拢到FeignClientFactoryBean之中

- 使用type类名做bean定义的名称,为空依序获取serviceId\name\value作为值,再+FeignClient作为别名

- 获取每一个@FeignClient(其部分功能和@RibbonClien注解类似)的属性值,以addPropertyValue(setter注入属性,即AUTO_BY_TYPE形式)形式封装为

AbstractBeanDefinition注册到容器中,比如

  type(类名)、name(依序获取serviceId\name\value)

  contextId(如果contextId为空,使用依序获取serviceId\name\value作为值)、

  url、path、fallback等直接取值

@FeignClient(value = "openFeign-provider",contextId = "openFeign-provide" ,path = "/test",configuration = xx.class,fallbackFactory = xx.class)
      public interface OpenFeignService {
          @PostMapping("/openfeign/provider/order2")
          Order createOrder2(@RequestBody Order order);
      }

   - 需要注意的是,fallbackFactory/fallback只有在支持hystrix下才有效,由feign.hystrix.FallbackFactory也可见

    @ConditionalOnMissingClass("feign.hystrix.HystrixFeign")

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {


   private ResourceLoader resourceLoader;
   private Environment environment;

   FeignClientsRegistrar() {
   }

   
   @Override
   public void setResourceLoader(ResourceLoader resourceLoader) {
      this.resourceLoader = resourceLoader;
   }

   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata,
         BeanDefinitionRegistry registry) {
      registerDefaultConfiguration(metadata, registry);
      registerFeignClients(metadata, registry);
   }

   private void registerDefaultConfiguration(AnnotationMetadata metadata,
         BeanDefinitionRegistry registry) {
      Map<String, Object> defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
      if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
         String name;
         if (metadata.hasEnclosingClass()) {
            name = "default." + metadata.getEnclosingClassName();
         }
         else {name = "default." + metadata.getClassName();}
         registerClientConfiguration(registry, name,defaultAttrs.get("defaultConfiguration"));
      }
   }

   public void registerFeignClients(AnnotationMetadata metadata,
         BeanDefinitionRegistry registry) {
      ClassPathScanningCandidateComponentProvider scanner = getScanner();
      scanner.setResourceLoader(this.resourceLoader);

      Set<String> basePackages;

      Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
      AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
      final Class<?>[] clients = attrs == null ? null: (Class<?>[]) attrs.get("clients");
      //如果@EnableFeignClients注解的clients为空
      if (clients == null || clients.length == 0) {
         scanner.addIncludeFilter(annotationTypeFilter);
         //获取@EnableFeignClients主键的valuebasePackagesbasePackageClasses属性指定的包路,如果都为空使用标志此注解的类本身路径
         //扫描添加了@FeignClient注解的类
         basePackages = getBasePackages(metadata);
      }
      else {
         //指定clients客户端类的处理
         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)));
      }

      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();
               Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
               //为空依次取contextId\value\name\serviceId;
               String name = getClientName(attributes);
               //使用name+FeignClientSpecification作为bean定义名,FeignClientSpecificationbean类型,封装了指定的配置类
               registerClientConfiguration(registry, name,attributes.get("configuration"));
               registerFeignClient(registry, annotationMetadata, attributes);
            }
         }
      }
   }

   private void registerFeignClient(BeanDefinitionRegistry registry,
         AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
      String className = annotationMetadata.getClassName();
      BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
      validate(attributes);
      definition.addPropertyValue("url", getUrl(attributes));
      definition.addPropertyValue("path", getPath(attributes));
      //依序获取serviceId\name\value作为name
      String name = getName(attributes);
      definition.addPropertyValue("name", name);
      //如果contextId为空,使用依序获取serviceId\name\value作为值
      String contextId = getContextId(attributes);
      definition.addPropertyValue("contextId", contextId);
      definition.addPropertyValue("type", className);
      definition.addPropertyValue("decode404", attributes.get("decode404"));
      definition.addPropertyValue("fallback", attributes.get("fallback"));
      definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
      definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

      String alias = contextId + "FeignClient";
      AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
      boolean primary = (Boolean) attributes.get("primary");
      beanDefinition.setPrimary(primary);
      String qualifier = getQualifier(attributes);
      if (StringUtils.hasText(qualifier)) {
         alias = qualifier;
      }
      BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,new String[] { alias });
      BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
   }

   
   
   protected ClassPathScanningCandidateComponentProvider getScanner() {
      return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
         @Override
         protected boolean isCandidateComponent(
               AnnotatedBeanDefinition beanDefinition) {
            boolean isCandidate = false;
            if (beanDefinition.getMetadata().isIndependent()) {
               if (!beanDefinition.getMetadata().isAnnotation()) {
                  isCandidate = true;
               }
            }
            return isCandidate;
         }
      };
   }


   
   private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
         Object configuration) {
      BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
      builder.addConstructorArgValue(name);
      builder.addConstructorArgValue(configuration);
      registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),builder.getBeanDefinition());
   }



}

  可以看出,关键逻辑又回到 FeignClientFactoryBean 拿到业务接口、@EnableFeignClient 和 @FeignClient 的数据后如何去构造代理类了,而 FeignClientFactoryBean 内部其实使用的是原生 Feign 的 API 来构建代理对象。

3、自动配置

配置的加载顺序如下

注:FeignRibbonClientAutoConfiguration 和FeignLoadBalancerAutoConfiguration功能基本一致,一般以FeignRibbonClientAutoConfiguration 为主

3.1 FeignRibbonClientAutoConfiguration

在存在ILoadBalancer.class, Feign.class的时候会进行加载,作用是

* 创建CachingSpringLoadBalancerFactory,用于创建FeignLoadBalancer对象

* 开启FeignHttpClientProperties类型属性对象,收集feign.httpclient.xxxx配置

  其超时配置会作用于底层httpClient客户端

* 依情况注入feign.Client接口的3个实现类,以HttpClientFeignLoadBalancedConfiguration为例,存在ApacheHttpClient类时会新建

①导入HttpClientFeignConfiguration,会使用ApacheHttpClien适配底层的HttpClient(CloseableHttpClient)接口的实现类

此HttpClient对象可能会被FeignAutoConfiguration配置的HttpClient bean覆盖,但没关系,两者的创建内容是一样的,

②会创建feign.Client底层接口的实现类,实现类型为LoadBalancerFeignClient,构造参数如下

- HttpClient:委托对象,为①创建ApacheHttpClient(CloseableHttpClient)适配类;

- SpringClientFactory :ribbon组件创建工厂,这个在RibbonAutoConfiguration里会创建,这里也包含了Ribbon的所有功能,是Feign基于Ribbon的最大原因;

- CachingSpringLoadBalancerFactory:这个在FeignRibbonClientAutoConfiguration里会创建

@ConditionalOnClass({ ILoadBalancer.class, Feign.class })
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.ribbon.enabled",
      matchIfMissing = true)
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(FeignAutoConfiguration.class)
@EnableConfigurationProperties({ FeignHttpClientProperties.class })
@Import({ HttpClientFeignLoadBalancedConfiguration.class,
      OkHttpFeignLoadBalancedConfiguration.class,
      DefaultFeignLoadBalancedConfiguration.class })
public class FeignRibbonClientAutoConfiguration {

   @Bean
   @Primary
   @ConditionalOnMissingBean
   @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
   public CachingSpringLoadBalancerFactory cachingLBClientFactory(
         SpringClientFactory factory) {
      return new CachingSpringLoadBalancerFactory(factory);
   }

   @Bean
   @Primary
   @ConditionalOnMissingBean
   @ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
   public CachingSpringLoadBalancerFactory retryabeCachingLBClientFactory(
         SpringClientFactory factory, LoadBalancedRetryFactory retryFactory) {
      return new CachingSpringLoadBalancerFactory(factory, retryFactory);
   }

   @Bean
   @ConditionalOnMissingBean
   public Request.Options feignRequestOptions() {
      return LoadBalancerFeignClient.DEFAULT_OPTIONS;
   }

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ApacheHttpClient.class)
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
@Import(HttpClientFeignConfiguration.class)
class HttpClientFeignLoadBalancedConfiguration {

   @Bean
   @ConditionalOnMissingBean(Client.class)
   public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
         SpringClientFactory clientFactory, HttpClient httpClient) {
      ApacheHttpClient delegate = new ApacheHttpClient(httpClient);
      return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
   }

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(CloseableHttpClient.class)
public class HttpClientFeignConfiguration {

   private final Timer connectionManagerTimer = new Timer(
         "FeignApacheHttpClientConfiguration.connectionManagerTimer", true);

   private CloseableHttpClient httpClient;

   @Autowired(required = false)
   private RegistryBuilder registryBuilder;

   @Bean
   @ConditionalOnMissingBean(HttpClientConnectionManager.class)
   public HttpClientConnectionManager connectionManager(
         ApacheHttpClientConnectionManagerFactory connectionManagerFactory,
         FeignHttpClientProperties httpClientProperties) {
      final HttpClientConnectionManager connectionManager = connectionManagerFactory
            .newConnectionManager(httpClientProperties.isDisableSslValidation(),
                  httpClientProperties.getMaxConnections(),
                  httpClientProperties.getMaxConnectionsPerRoute(),
                  httpClientProperties.getTimeToLive(),
                  httpClientProperties.getTimeToLiveUnit(), this.registryBuilder);
      this.connectionManagerTimer.schedule(new TimerTask() {
         @Override
         public void run() {
            connectionManager.closeExpiredConnections();
         }
      }, 30000, httpClientProperties.getConnectionTimerRepeat());
      return connectionManager;
   }

   @Bean
   @ConditionalOnProperty(value = "feign.compression.response.enabled",
         havingValue = "false", matchIfMissing = true)
   public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory,
         HttpClientConnectionManager httpClientConnectionManager,
         FeignHttpClientProperties httpClientProperties) {
      this.httpClient = createClient(httpClientFactory.createBuilder(),
            httpClientConnectionManager, httpClientProperties);
      return this.httpClient;
   }

   private CloseableHttpClient createClient(HttpClientBuilder builder,
         HttpClientConnectionManager httpClientConnectionManager,
         FeignHttpClientProperties httpClientProperties) {
      RequestConfig defaultRequestConfig = RequestConfig.custom()
            .setConnectTimeout(httpClientProperties.getConnectionTimeout())
            .setRedirectsEnabled(httpClientProperties.isFollowRedirects()).build();
      CloseableHttpClient httpClient = builder
            .setDefaultRequestConfig(defaultRequestConfig)
            .setConnectionManager(httpClientConnectionManager).build();
      return httpClient;
   }


}

3.2 FeignAutoConfiguration

与RibbonAutoConfiguration配置类似

* 收集配置类List<FeignClientSpecification> configurations

收集@EnableFeignClients、@FeignClient定义封装好的配置类

* 启动文件配置

- 启动FeignClientProperties属性配置feign.client.xxxx

- 启动FeignHttpClientProperties属性配置feign.httpclient.xxxx


* 创建FeignContext extends NamedContextFactory<FeignClientSpecification>

  和SpringClientFactory类似,这里为每一个指定的name 创建一个上下文,里面会注册配置表中指定name和默认FeignClientsConfiguration默认配置的数据

  每个上下文里包含可每一个服务独自指定的和全局默认的配信息,如 Logger.Level:日志级别、 Retryer: 重试机制、Client:Http客户端接口、Decoder:解码器等

  

* Targeter类的创建

  会依据是否存在feign.hystrix.HystrixFeign类来创建DefaultTargeter或者HystrixTargeter实现类

* feign.Client接口的实现类,和FeignRibbonClientAutoConfiguration里的类似,

- 比如会根据是否有ApacheHttpClient,会使用ApacheHttpClien适配底层的HttpClient(CloseableHttpClient)接口的实现类

  创建逻辑是独立的,是和Feign没有强关联。

  - 注意这里创建的ApacheHttpClient会使用FeignHttpClientProperties(feign.httpclient.xxxx)属性类的值

    例如超时时间、连接池相关的设置


@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({ FeignClientProperties.class,
      FeignHttpClientProperties.class })
@Import(DefaultGzipDecoderConfiguration.class)
public class FeignAutoConfiguration {

   @Autowired(required = false)
   private List<FeignClientSpecification> configurations = new ArrayList<>();

   @Bean
   public HasFeatures feignFeature() {
      return HasFeatures.namedFeature("Feign", Feign.class);
   }

   @Bean
   public FeignContext feignContext() {
      FeignContext context = new FeignContext();
      context.setConfigurations(this.configurations);
      return context;
   }

   @Configuration(proxyBeanMethods = false)
   @ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
   protected static class HystrixFeignTargeterConfiguration {

      @Bean
      @ConditionalOnMissingBean
      public Targeter feignTargeter() {
         return new HystrixTargeter();
      }

   }

   @Configuration(proxyBeanMethods = false)
   @ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
   protected static class DefaultFeignTargeterConfiguration {

      @Bean
      @ConditionalOnMissingBean
      public Targeter feignTargeter() {
         return new DefaultTargeter();
      }

   }

   @Configuration(proxyBeanMethods = false)
   @ConditionalOnClass(ApacheHttpClient.class)
   @ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
   @ConditionalOnMissingBean(CloseableHttpClient.class)
   @ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
   protected static class HttpClientFeignConfiguration {

      private final Timer connectionManagerTimer = new Timer(
            "FeignApacheHttpClientConfiguration.connectionManagerTimer", true);

      @Autowired(required = false)
      private RegistryBuilder registryBuilder;

      private CloseableHttpClient httpClient;

      @Bean
      @ConditionalOnMissingBean(HttpClientConnectionManager.class)
      public HttpClientConnectionManager connectionManager(
            ApacheHttpClientConnectionManagerFactory connectionManagerFactory,
            FeignHttpClientProperties httpClientProperties) {
         final HttpClientConnectionManager connectionManager = connectionManagerFactory
               .newConnectionManager(httpClientProperties.isDisableSslValidation(),
                     httpClientProperties.getMaxConnections(),
                     httpClientProperties.getMaxConnectionsPerRoute(),
                     httpClientProperties.getTimeToLive(),
                     httpClientProperties.getTimeToLiveUnit(),
                     this.registryBuilder);
         this.connectionManagerTimer.schedule(new TimerTask() {
            @Override
            public void run() {
               connectionManager.closeExpiredConnections();
            }
         }, 30000, httpClientProperties.getConnectionTimerRepeat());
         return connectionManager;
      }

      @Bean
      public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory,
            HttpClientConnectionManager httpClientConnectionManager,
            FeignHttpClientProperties httpClientProperties) {
         RequestConfig defaultRequestConfig = RequestConfig.custom()
               .setConnectTimeout(httpClientProperties.getConnectionTimeout())
               .setRedirectsEnabled(httpClientProperties.isFollowRedirects())
               .build();
         this.httpClient = httpClientFactory.createBuilder()
               .setConnectionManager(httpClientConnectionManager)
               .setDefaultRequestConfig(defaultRequestConfig).build();
         return this.httpClient;
      }

      @Bean
      @ConditionalOnMissingBean(Client.class)
      public Client feignClient(HttpClient httpClient) {
         return new ApacheHttpClient(httpClient);
      }

      @PreDestroy
      public void destroy() throws Exception {
         this.connectionManagerTimer.cancel();
         if (this.httpClient != null) {
            this.httpClient.close();
         }
      }

   }

   @Configuration(proxyBeanMethods = false)
   @ConditionalOnClass(OkHttpClient.class)
   @ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
   @ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
   @ConditionalOnProperty("feign.okhttp.enabled")
   protected static class OkHttpFeignConfiguration {

      private okhttp3.OkHttpClient okHttpClient;

      @Bean
      @ConditionalOnMissingBean(ConnectionPool.class)
      public ConnectionPool httpClientConnectionPool(
            FeignHttpClientProperties httpClientProperties,
            OkHttpClientConnectionPoolFactory connectionPoolFactory) {
         Integer maxTotalConnections = httpClientProperties.getMaxConnections();
         Long timeToLive = httpClientProperties.getTimeToLive();
         TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
         return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
      }

      @Bean
      public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory,
            ConnectionPool connectionPool,
            FeignHttpClientProperties httpClientProperties) {
         Boolean followRedirects = httpClientProperties.isFollowRedirects();
         Integer connectTimeout = httpClientProperties.getConnectionTimeout();
         Boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
         this.okHttpClient = httpClientFactory.createBuilder(disableSslValidation)
               .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
               .followRedirects(followRedirects).connectionPool(connectionPool)
               .build();
         return this.okHttpClient;
      }

      @PreDestroy
      public void destroy() {
         if (this.okHttpClient != null) {
            this.okHttpClient.dispatcher().executorService().shutdown();
            this.okHttpClient.connectionPool().evictAll();
         }
      }

      @Bean
      @ConditionalOnMissingBean(Client.class)
      public Client feignClient(okhttp3.OkHttpClient client) {
         return new OkHttpClient(client);
      }

   }

}

3.3 FeignClientsConfiguration默认Name容器配置

包括了Fegin可配置的所有组件:

* Decoder解码器

 默认为OptionalDecoder,用于把远程的repose转为feign接口方法对应的类型

* SpringEncoder编码器

  - 默认为SpringEncoder,会接受容器中的ObjectFactory<HttpMessageConverters> HttpMessageConverters

- 会把请求体数据(可以从feign接口参数中获取到)转换为request中指定ContentType的数据格式,作为RequestTemplate的body

*Contract请求信息解析器

  - 默认为SpringMvcContract,可以结合SpringMVC的相关注解,把一个feign接口解析为List<MethodMetadata>,一个方法对应个MethodMetadata

  - MethodMetadata里包含一个RequestTemplate template和方法上的信息

   ①RequestTemplate即请求模板,基于SpringMVC约定的注解,可以获取到template().uri/header/method()信息

   ②方法上的信息:如普通参数(作为请求体)的参数位置下标,所有@Param的name存于List<String> formParams,

                   添加了@QueryMap/HeaderMap注解的参数的位置

* Builder构造者

  - 默认为Feign.builder,用于配置contract/Client /Retryer/Logger/Encoder/Decoderd等,最后封装到ReflectiveFeign对象中

@Configuration(proxyBeanMethods = false)
public class FeignClientsConfiguration {

   @Autowired
   private ObjectFactory<HttpMessageConverters> messageConverters;
   @Autowired(required = false)
   private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();
   @Autowired(required = false)
   private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();
   @Autowired(required = false)
   private Logger logger;
   @Autowired(required = false)
   private SpringDataWebProperties springDataWebProperties;

   @Bean
   @ConditionalOnMissingBean
   public Decoder feignDecoder() {
      return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
   }

   @Bean
   @ConditionalOnMissingBean
   @ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
   public Encoder feignEncoder() {
      return new SpringEncoder(this.messageConverters);
   }

   @Bean
   @ConditionalOnClass(name = "org.springframework.data.domain.Pageable")
   @ConditionalOnMissingBean
   public Encoder feignEncoderPageable() {
      PageableSpringEncoder encoder = new PageableSpringEncoder(
            new SpringEncoder(this.messageConverters));
      if (springDataWebProperties != null) {
         encoder.setPageParameter(springDataWebProperties.getPageable().getPageParameter());
         encoder.setSizeParameter(springDataWebProperties.getPageable().getSizeParameter());
         encoder.setSortParameter( springDataWebProperties.getSort().getSortParameter());
      }
      return encoder;
   }

   @Bean
   @ConditionalOnMissingBean
   public Contract feignContract(ConversionService feignConversionService) {
      return new SpringMvcContract(this.parameterProcessors, feignConversionService);
   }
   @Bean
   public FormattingConversionService feignConversionService() {
      FormattingConversionService conversionService = new DefaultFormattingConversionService();
      for (FeignFormatterRegistrar feignFormatterRegistrar : this.feignFormatterRegistrars) {
         feignFormatterRegistrar.registerFormatters(conversionService);
      }
      return conversionService;
   }

   @Bean
   @ConditionalOnMissingBean
   public Retryer feignRetryer() {
      return Retryer.NEVER_RETRY;
   }

   @Bean
   @Scope("prototype")
   @ConditionalOnMissingBean
   public Feign.Builder feignBuilder(Retryer retryer) {
      return Feign.builder().retryer(retryer);
   }

   @Bean
   @ConditionalOnMissingBean(FeignLoggerFactory.class)
   public FeignLoggerFactory feignLoggerFactory() {
      return new DefaultFeignLoggerFactory(this.logger);
   }

   @Bean
   @ConditionalOnClass(name = "org.springframework.data.domain.Page")
   public Module pageJacksonModule() {
      return new PageJacksonModule();
   }

   @Configuration(proxyBeanMethods = false)
   @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
   protected static class HystrixFeignConfiguration {

      @Bean
      @Scope("prototype")
      @ConditionalOnMissingBean
      @ConditionalOnProperty(name = "feign.hystrix.enabled")
      public Feign.Builder feignHystrixBuilder() {
         return HystrixFeign.builder();
      }

   }

}

4、@FeignClient代理类创建(基于FeignClientFactoryBean)

4.1、概述

* 在@EnableFeignClients注解阶段就把@FeignClient接口转为FeignClientFactoryBean注册容器中了

  封装好了从@FeignClient注解解析后的所有属性:

   @FeignClient(value/name = "openFeign-provider",contextId = "openFeign-provide" ,path = "/test",configuration = xx.class,fallbackFactory = xx.class)

private Class<?> type;
    private String name;
    private String url;
    private String contextId;
    private String path;
    private boolean decode404;
    private ApplicationContext applicationContext;
    private Class<?> fallback = void.class;
    private Class<?> fallbackFactory = void.class;

* Fegin 使用的是 JDK 动态代理技术来生成实现类的,因此 Feign 的使用必须要有接口,一个feign接口每个方法有 @RequestMapping

虽然我们可以在 java.lang.reflect.InvocationHandler#invoke 的方法入参 Method 中去解析 @RequestMapping 拿url,

但需要注意的是,大多数开源框架很忌讳在运行时高频使用JDK的反射,因为这样非常影响执行效率

所以在 Feign 使用 JDK动态代理技术时,需要提前将接口带 @RequestMapping 方法解析出来。

4.2、Feign.Builder组件封装对象

步骤如下:

* 获取feign上下文容器FeignContext context,以每一个ContextId为key,即每一个ContextId一个单独的容器上下文

* 基于FeignContext和文件属性配置类获取用户定义或者默认的组件实现类,存于Builder中

  - 从Name容器中获取Feign.Builder

- 组装必须组件Logger、Encoder、Decoder、Contract

Feign.Builder builder = get(context, Feign.Builder.class).logger(logger).encoder(get(context, Encoder.class)).decoder(get(context, Decoder.class)).contract(get(context, Contract.class));

- 组装可选组件

获取父Spring容器中获取FeignClientProperties(在FeignAutoConfiguration 中会启用),即feign.client.xxx

会从不同维度依次获取Logger.Level、Retryer、ErrorDecoder、Request.Options、RequestInterceptor、QueryMapEncoder组装到Feign.Builder,后面的会覆盖前面的

①从Name容器中获取可选组件

②获取feign.client.default.xxxx,映射为FeignClientConfiguration对象,从此配置中获取可选组件     

③获取feign.client.contextId.xxxx,映射为FeignClientConfiguration对象,从此配置中获取可选组件

如果此FeignClientProperties为全局默认,即feign.client.defaultToProperties = true;--默认,走①②③

如果此FeignClientProperties不为全局默认,走②③

如果此FeignClientProperties不存在,走①

* 判断是否配置了url属性,选择不同的HttpClient,进行组装builder.client(client);

①如果没有,使用增强的HttpClient进行访问。比如提供负载均衡的客户端LoadBalancerFeignClient类,所有需要使用基于服务实例的负载均衡进行通信

  - 会拼接name/name属性和path属性到url属性中,例如this.url = http://openFeign-provider/test

    简单的封装到HardCodedTarget(this.type--接口类型, this.name, this.url)

  - 从Name容器(没有就到Spring容器)中获取feign.Client类型对象,例如FeignRibbonClientAutoConfiguration引入的LoadBalancerFeignClient

其内部委托了实际的通信工具ApacheHttpClient

②如果存在url,流程和①类似,区别在于此时feign.Client类型对象取的其委托委托了实际的通信工具

使用LoadBalancerFeignClient/FeignBlockingLoadBalancerClient内部委托的,使用其.getDelegate()获取到底层没有负载功能的feign.Client类型对象

比如LoadBalancerFeignClient的委托类ApacheHttpClient,适配底层的HttpClient(CloseableHttpClient)实例从而实现了feign.Client类型,是没有负载均衡功能的

* 最后使用Targeter进行目标代理,会根据是否存在feign.hystrix.HystrixFeign类获取DefaultTargeter或者HystrixTargeter---流程见下节

  - targeter.target(this, builder, context, HardCodedTarget(this.type--接口类型, this.name, this.url));

    - 例如DefaultTargete会使用(Feign.Builder)feign.target(target)会创建this.type--接口类型的接口代理类,增强类是FeignInvocationHandler

class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
   
   private Class<?> type;
   private String name;
   private String url;
   private String contextId;
   private String path;
   private boolean decode404;
   private ApplicationContext applicationContext;
   private Class<?> fallback = void.class;
   private Class<?> fallbackFactory = void.class;


   @Override
   public Object getObject() throws Exception {
      return getTarget();
   }
   <T> T getTarget() {
      //获取feign容器
      FeignContext context = this.applicationContext.getBean(FeignContext.class);
      //根据配置的优先级在Builder中设置各个组件的实现
      Feign.Builder builder = feign(context);

      //如果没有url属性,使用增强的cilent进行访问。比如提供负载均衡的客户端LoadBalancerFeignClient
      if (!StringUtils.hasText(this.url)) {
         if (!this.name.startsWith("http")) {
            this.url = "http://" + this.name;
         }
         else {
            this.url = this.name;
         }

//拼接name属性和path属性
         this.url += cleanPath();
         //这里builder.client(client);client提供负载均衡的客户端,之后使用targeter.target进行代理
         return (T) loadBalance(builder, context,
               new HardCodedTarget<>(this.type, this.name, this.url));
      }
      //如果存在url,使用底层的HttpClient进行直接访问
      if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
         this.url = "http://" + this.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();
         }
         builder.client(client);
      }
      Targeter targeter = get(context, Targeter.class);
      return (T) targeter.target(this, builder, context,
            new HardCodedTarget<>(this.type, this.name, url));
   }
   
   
   protected Feign.Builder feign(FeignContext context) {
      FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
      Logger logger = loggerFactory.create(this.type);

      //添加必要的组件
      Feign.Builder builder = get(context, Feign.Builder.class)
            // required values
            .logger(logger)
            .encoder(get(context, Encoder.class))
            .decoder(get(context, Decoder.class))
            .contract(get(context, Contract.class));
      //根据文件配置、java配置类进行配置,按照优先级进行覆盖,代码略
      configureFeign(context, builder);
      return builder;
   }


protected <T> T get(FeignContext context, Class<T> type) {
   T instance = context.getInstance(this.contextId, type);
   if (instance == null) {
      throw new IllegalStateException(
            "No bean found of type " + type + " for " + this.contextId);
   }
   return instance;
}


   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();
   }
   

   //gettersetter

}

4.3、使用Targete创建代理类流程(默认DefaultTargeter

4.3.1 Targeter接口

* 作用

  用于创建feign接口的代理类,会先解析相关必要的信息,在代理增强逻辑中进行调用,从而完成这个通信流程

* target接口参数如下,返回T就是最终代理类

  - FeignClientFactoryBean:feign代理接口对应的FactoryBean,里面封装好了从@FeignClient注解解析后的所有属性:

   @FeignClient(value/name = "openFeign-provider",contextId = "openFeign-provide" ,path = "/test",configuration = xx.class,fallbackFactory = xx.class)

  - Feign.Builder构造者:里面包含的一个feign代理类所需的所有必要的组件和可选组件

   组装必须组件Logger、Encoder、Decoder、Contract

   组装可选组件Logger.Level、Retryer、ErrorDecoder、Request.Options、RequestInterceptor、QueryMapEncoder  

  - FeignContext context:feign的Name容器功能,可以获取一个contextId(如果contextId为空,使用依序获取serviceId\name\value作为值)维度的容器中的bean

  - HardCodedTarget(this.type--接口类型, this.name, this.url):简单的包装类,此this.url为 http://服务名/path;或者http://直接域名/path;

* 调用时机

  在FeignClientFactoryBean的getObject()中就会处理好target接口这个所需的所有参数(见上),在调用此接口经常创建最终的代理类

interface Targeter {
   <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
         FeignContext context, Target.HardCodedTarget<T> target);

}

4.3.2 DefaultTargeter实现类

代理类会根据调用的方法来直接找到已经提前准备好的对应的 MethodHandler,直接调用即可完成Feign的使命,根据上面的使用方法,我们不难猜到 MethodHandler 里面有HTTP调用的相关信息(这些信息之前是在接口方法定义的 @RequestMapping 或 @RequestLine 之中),而且 MethodHandler#invoke 会完成真正的HTTP调用并将结果反序列化成原接口方法的返回值对象

* 使用DefaultTargeter的target方法,底层为Feign.Builder类target方法

  - 使用build()方法创建ReflectiveFeign

- 在使用此ReflectiveFeign的newInstance(target)创建代理


//DefaultTargeter
class DefaultTargeter implements Targeter {
    @Override
    public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
                        FeignContext context, Target.HardCodedTarget<T> target) {
        return feign.target(target);
    }
}

//Feign.Builder类的feign.target(target)
public <T> T target(Target<T> target) {
    return build().newInstance(target);
}

4.3.2.1 ReflectiveFeign的build构建

* 基于ReflectiveFeign创建最终代理类的实现,先调用build()创建ReflectiveFeign,会创建好ReflectiveFeign所需的参数

  ①SynchronousMethodHandler.Factory synchronousMethodHandlerFactory

- new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy);

    - 是一个简单的工厂类,里面的create方法就会返回一个SynchronousMethodHandler,其内也包含了这些参数配置

②ParseHandlersByName handlersByName

- new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,errorDecoder, synchronousMethodHandlerFactory);

- 也是一个简单的包装类,唯一的方法apply用于解析一个feign接口,解析每一个方法为一个对应的MethodHandler(见下节)

Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);

   ③创建ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder)

     其中InvocationHandlerFactory默认为InvocationHandlerFactory.Default();

public Feign build() {
  SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors,

    logger,logLevel, decode404, closeAfterDecode, propagationPolicy);
  ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
           errorDecoder, synchronousMethodHandlerFactory);
  return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}


static class Factory {

  private final Client client;
  private final Retryer retryer;
  private final List<RequestInterceptor> requestInterceptors;
  private final Logger logger;
  private final Logger.Level logLevel;
  private final boolean decode404;
  private final boolean closeAfterDecode;
  private final ExceptionPropagationPolicy propagationPolicy;

  Factory(Client client, Retryer retryer, List<RequestInterceptor> requestInterceptors,
      Logger logger, Logger.Level logLevel, boolean decode404, boolean closeAfterDecode,
      ExceptionPropagationPolicy propagationPolicy) {
    this.client = checkNotNull(client, "client");
    this.retryer = checkNotNull(retryer, "retryer");
    this.requestInterceptors = checkNotNull(requestInterceptors, "requestInterceptors");
    this.logger = checkNotNull(logger, "logger");
    this.logLevel = checkNotNull(logLevel, "logLevel");
    this.decode404 = decode404;
    this.closeAfterDecode = closeAfterDecode;
    this.propagationPolicy = propagationPolicy;
  }

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

4.3.2.2 调用ReflectiveFeign.newInstance创建代理类

①基于ParseHandlersByName为每一个方法创建MethodHandler(默认为SynchronousMethodHandler

Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);

②在形成方法反射对象method到MethodHandler的映射结果Map<Method, MethodHandler> methodToHandler

   - 如果是public非abstract,非synthetic,非static 的方法,且是interface方法,使用DefaultMethodHandler类作为MethodHandler(也是一个增强)

即非接口方法的代理实际上是直接调用原对象的方法

   - 如果是接口指定的方法,在methodToHandler中找到对应方法的处理类

methodToHandler从ParseHandlersByName.apply返回的结果集中获取,如果获取不到就使用原menthod

  ③使用InvocationHandlerFactory的create(target, methodToHandler)创建InvocationHandler增强类

new ReflectiveFeign.FeignInvocationHandler(target, methodToHandler);

  ④使用JDK代理创建工具创建增强类,其invoke方法就是根据需要调用的方法method从methodToHandler获取对应的MethodHandler,调用MethodHandler.invoke(args)

    - InvocationHandler handler = factory.create(target, methodToHandler);

     T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[] {target.type()}, handler);

- 增强功能最终调用的是SynchronousMethodHandler.invoke

  

public class ReflectiveFeign extends Feign {

  private final ParseHandlersByName targetToHandlersByName;
  private final InvocationHandlerFactory factory;
  private final QueryMapEncoder queryMapEncoder;

  ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory, QueryMapEncoder queryMapEncoder) {
    this.targetToHandlersByName = targetToHandlersByName;
    this.factory = factory;
    this.queryMapEncoder = queryMapEncoder;
  }

  @SuppressWarnings("unchecked")
  @Override
  public <T> T newInstance(Target<T> target) {
    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)));
      }
    }
    InvocationHandler handler = factory.create(target, methodToHandler);
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
        new Class<?>[] {target.type()}, handler);

    for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
      defaultMethodHandler.bindTo(proxy);
    }
    return proxy;
  }

  static class FeignInvocationHandler implements InvocationHandler {

    private final Target target;
    private final Map<Method, MethodHandler> dispatch;

    FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
      this.target = checkNotNull(target, "target");
      this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      if ("equals".equals(method.getName())) {
        try {
          Object otherHandler =
              args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
          return equals(otherHandler);
        } catch (IllegalArgumentException e) {
          return false;
        }
      } else if ("hashCode".equals(method.getName())) {
        return hashCode();
      } else if ("toString".equals(method.getName())) {
        return toString();
      }

      return dispatch.get(method).invoke(args);
    }

   

    //略

}

4.4、MethodHandler的创建

4.4.1 整体流程

 Map<String, MethodHandler> nameToHandler = ParseHandlersByName.apply(target);

使用ParseHandlersByName的apply方法生成每个接口方法的MethodHandler,MethodHandler的默认实现为SynchronousMethodHandler

* 使用contract.parseAndValidatateMetadata获取每个接口方法的元数据MethodMetadata

- 包括RequestTemplate、接口方法的返回类类型,以及经过对注解等信息获取每个方法对应的url、请求头、请求体等信息及参数位置下标

  - Contract的默认实现是SpringMvcContract,它支持解析@RequestMapping等注解,获取相关的信息

* 遍历每一个MethodMetadata,解析为对应的BuildTemplateByResolvingArgs

  - !md.formParams().isEmpty() && md.template().bodyTemplate() == null) ,即存在form且不存在请求体时

   封装为BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder);

  - md.bodyIndex() != null,即存在feign接口存在指定请求体参数时

   封装为BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder);

  - 其余情况

封装为BuildTemplateByResolvingArgs(md, queryMapEncoder);

* 使用MethodHandler工厂创建把每一个MethodMetadata创建对应的MethodHandler,其中参数包含了所有feign组件已经上一步解析后的BuildTemplateByResolvingArgs

new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger,

          logLevel, md, buildTemplateFromArgs, options, decoder,

          errorDecoder, decode404, closeAfterDecode, propagationPolicy);

* 返回解析后的Map<方法标志key, MethodHandler>

public Map<String, MethodHandler> apply(Target key) {
    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) {
        buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
      } else if (md.bodyIndex() != null) {
        buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
      } else {
        buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder);
      }
      result.put(md.configKey(),
          factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
    }
    return result;
  }
}

4.4.2 MethodMetadata元数据类(以SpringMvcContract解析为例)

class MethodMetadata {
    // key=OrderFeign#post(Order)
    private String configKey;
    // 方法返回类型=Order
    private transient Type returnType;
    // URL类型的参数的下标
    private Integer urlIndex;
    // 请求体位置不同类型的对象(没有标注http相关注解)。只能有一个),但可以存在多个Optional类型的参数
    private Integer bodyIndex;

// 请求体类型
    private transient Type bodyType;
    // 消息头位置表示请求头的参数的位置)、HeaderMap/RequestHeader注解、
    private Integer headerMapIndex;
    // queryMap位置,最终会作为url的查询参数(RequestTemplate的queries--会作为"&"查询参数),例如带有@SpringQueryMap参数、带有@RequestParam且为Map类型的参数
    private Integer queryMapIndex;
    private boolean queryMapEncoded;
    // 请求模板会在里面存储解析收数据 例如method、url(从@RequestMapping的value)、@RequestParam注解指定的值(RequestTemplate的queries)会存于此,template().query(name, query))

、从@RequestMapping获取ACCEP/等、Feign中的scheme(即协议类型,如http或https)通常由接口方法上的URL注解指定,如果没有指定,Feign会尝试从配置中获取默认的scheme。如果配置中也没有指定,Feign默认使用http协议
    private final RequestTemplate template = new RequestTemplate(); 

// @PathVariable的value/name的名称,此name名称RequestTemplate的queries和heards都不存在值时,且url上的#部分不存在,会加入此formParams
    private final List<String> formParams = new ArrayList();

//@Param、@PathVariabl、@RequestHeader、@RequestParam中的value/name的名称都会存于此(已经对应的参数下标)
    private final Map<Integer, Collection<String>> indexToName = new LinkedHashMap();

//对于http功能的注解(如@PathVariable)的参数,会有一个对应Expander,用于把此值转为String
    private final Map<Integer, Class<? extends Expander>> indexToExpanderClass = new LinkedHashMap();
    private final Map<Integer, Boolean> indexToEncoded = new LinkedHashMap();

//基于conversionService获取能够把参数类转为字符串的转换器器,如果没有为null
    private transient Map<Integer, Expander> indexToExpander;
    private BitSet parameterToIgnore = new BitSet();
    // 是否忽略该方法
    private boolean ignored;
    // 需要代理的接口类型
    private transient Class<?> targetType;
    // 接口中的方法 =public abstract pojo.Order account.OrderFeign.post(pojo.Order)
    private transient Method method;
    // 警告级别
    private final transient List<String> warnings = new ArrayList();
    
 }

4.4.3 Contract解析阶段为MethodMetadata集合(SpringMvcContract实现)

4.4.3.1 Contract 接口

只有一个parseAndValidatateMetadata方法,用于把指定的Feign接口类生成List<MethodMetadata>

public interface Contract {
  List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType);

}

4.4.3.2 BaseContract类

  实现了parseAndValidatateMetadata整体实现流程:

  * 接口的校验

   接口上不能有泛型变量、接口最多有一个父接口、父接口存在时,父接口的父接口不能存在

  * 开始遍历每一个接口方法,需要过滤掉Object的方法、static方法、default(default是指public非abstract,非synthetic,非static 的方法,且是interface方法)方法

    调用parseAndValidateMetadata进行解析成MethodMetadata

①设置好MethodMetadata的targetType(即Feign接口类型)、method(反射方法)、returnType、configKey

②调用抽象方法processAnnotationOnClass处理接口(包括父接口)上的注解

③调用抽象方法processAnnotationOnMethod处理接口方法的每一个注解

④处理接口参数的注解,遍历每一个参数,接口参数一般分为几类:标记了http相关注解的;URI类型的;Request.Options类型的,普通类型

  - 执行调用抽象方法processAnnotationsOnParameter判断参数注解是否属于isHttpAnnotation(默认flase)

      - 如果参数类型是否是URI,有了就设置MethodMetadata的urlIndex为此参数位置

      - 如果参数是标记了http相关注解(isHttpAnnotation为true)的且为非Request.Options类型的,即普通类型的

会设置为MethodMetadata的bodyIndex和bodyType,只能设置一次,多个会报错

⑤如果MethodMetadata .headerMapIndex()或者queryMapIndex存在

进行headerMap和queryMap进行Map类型的校验,只允许此参数类型为Map<String,String>类

abstract class BaseContract implements Contract {
    @Override
    public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
        //接口上不能有泛型变量
        checkState(targetType.getTypeParameters().length == 0, "Parameterized types unsupported: %s",targetType.getSimpleName());
        //接口最多有一个父接口
        checkState(targetType.getInterfaces().length <= 1, "Only single inheritance supported: %s",targetType.getSimpleName());
        //父接口存在时,父接口的父接口不能存在
        if (targetType.getInterfaces().length == 1) {
            checkState(targetType.getInterfaces()[0].getInterfaces().length == 0,"Only single-level inheritance supported: %s",targetType.getSimpleName());
        }

        final Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
        //遍历接口方法
        for (final Method method : targetType.getMethods()) {
            //过滤掉Object的方法、static方法、defaultdefault是指publicabstract,非synthetic,非static 的方法,且是interface方法)方法
            if (method.getDeclaringClass() == Object.class ||(method.getModifiers() & Modifier.STATIC) != 0 ||Util.isDefault(method)) {
                continue;
            }
            //解析出每个方法的元数据 MethodMetadata
            final MethodMetadata metadata = parseAndValidateMetadata(targetType, method);
            checkState(!result.containsKey(metadata.configKey()), "Overrides unsupported: %s",metadata.configKey());
            result.put(metadata.configKey(), metadata);
        }
        return new ArrayList<>(result.values());
    }

    //解析出每个方法的元数据 MethodMetadata
    protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
        final MethodMetadata data = new MethodMetadata();
        data.targetType(targetType);
        data.method(method);
        data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
        data.configKey(Feign.configKey(targetType, method));
        if (targetType.getInterfaces().length == 1) {
            //处理父接口上的注解,留给子类实现
            processAnnotationOnClass(data, targetType.getInterfaces()[0]);
        }
        //处理当前接口上的注解,留给子类实现
        processAnnotationOnClass(data, targetType);

        for (final Annotation methodAnnotation : method.getAnnotations()) {
            //处理接口方法上的注解,留给子类实现
            processAnnotationOnMethod(data, methodAnnotation, method);
        }
        if (data.isIgnored()) {return data;
        }
        checkState(data.template().method() != null,"Method %s not annotated with HTTP method type (ex. GET, POST)%s",data.configKey(), data.warnings());
        //方法参数类型
        final Class<?>[] parameterTypes = method.getParameterTypes();
        final Type[] genericParameterTypes = method.getGenericParameterTypes();
        //参数注解:Annotation[i][j]表示第i个参数的注解集合
        final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        final 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 (isHttpAnnotation) {data.ignoreParamater(i); }

            //参数类型是否是URI,有了就使用,没有就使用默认的
            if (parameterTypes[i] == URI.class) {
                data.urlIndex(i);
            } else if (!isHttpAnnotation && parameterTypes[i] != Request.Options.class) {
                //请求体的校验:bodyIndexbodyType只能设置一次,就非httpOptions类型的参数只能存在一个
                if (data.isAlreadyProcessed(i)) {
                    checkState(data.formParams().isEmpty() || data.bodyIndex() == null,"Body parameters cannot be used with form parameters.%s", data.warnings());
                } else {
                    checkState(data.formParams().isEmpty(),"Body parameters cannot be used with form parameters.%s", data.warnings());
                    checkState(data.bodyIndex() == null,"Method has too many Body parameters: %s%s", method, data.warnings());
                    data.bodyIndex(i);
                    data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i]));
                }
            }
        }

        //headerMapqueryMap进行Ma类型的校验
        if (data.headerMapIndex() != null) {
            checkMapString("HeaderMap", parameterTypes[data.headerMapIndex()],
                    genericParameterTypes[data.headerMapIndex()]);
        }
        if (data.queryMapIndex() != null) {
            if (Map.class.isAssignableFrom(parameterTypes[data.queryMapIndex()])) {
                checkMapKeys("QueryMap", genericParameterTypes[data.queryMapIndex()]);
            }
        }

        return data;
    }

}

4.4.3.3 SpringMvcContract

   @Bean
   @ConditionalOnMissingBean
   public Contract feignContract(ConversionService feignConversionService) {
      return new SpringMvcContract(this.parameterProcessors, feignConversionService);
   }

* 构造参数值

①List<AnnotatedParameterProcessor>:参数注解的处理器,如下

        //MatrixVariable 注解

annotatedArgumentResolvers.add(new MatrixVariableParameterProcessor());

//PathVariable 注解

annotatedArgumentResolvers.add(new PathVariableParameterProcessor());

//RequestParam 注解

annotatedArgumentResolvers.add(new RequestParamParameterProcessor());

//RequestHeader 注解

annotatedArgumentResolvers.add(new RequestHeaderParameterProcessor());

//SpringQueryMap 注解

annotatedArgumentResolvers.add(new QueryMapParameterProcessor());

//RequestPart 注解

annotatedArgumentResolvers.add(new RequestPartParameterProcessor());

②ConversionService feignConversionService:默认为DefaultFormattingConversionService,进行类型转换


 

* 重写和实现抽象方法

  ①重写核心方法parseAndValidateMetadata

    - 先调用父类parseAndValidateMetadata,这里面也会回调这边的抽象子类实现

    - 如果存在类上的@RequestMapping,在方法注解解析后没有设置ACCEPT\CONTENT_TYPE时,调用parseProduces和parseConsumes设置,即使用父类的设置

    - 如果存在类上的@RequestMapping,调用parseHeaders设置请求头

②实现抽象方法processAnnotationOnClass处理接口(包括父接口)上的注解

获取RequestMapping的value,作为MethodMetadata中RequestTemplate的uri

data.template().uri(pathValue);

  ③实现抽象方法processAnnotationOnMethod处理接口方法的每一个方法上注解的解析

- 获取RequestMapping注解,取http访问方法(只能有一个)执行data.template().method(),和url(追加类上的)执行data.template().uri(pathValue, true);

- 调用parseProduces/parseConsumes/parseHeaders方法,取produces/consumes/headers属性作为RequestTemplate的ACCEP/CONTENT_TYPE/请求头

  ④实现抽象方法processAnnotationsOnParameter判断参数,以判断是否为http相关注解的标志

- 遍历一个参数的所有注解,调用对应的处理类进行处理,设置是否为http相关注解的标志下, 其中也会处理一些data.template().xxx的值

- 如下解析器对应的注解均是isHttpAnnotation = true

  * PathVariableParameterProcessor:

获取@PathVariable注解上的name值,执行AnnotatedParameterContext.setParameterName(name),会data.indexToName().put(i, names);

data.template().queries()和headers()不存在此name时,执行data.formParams().add(name);

      * QueryMapParameterProcessor

         获取第一个标注了@SpringQueryMap注解的参数,执行metadata.queryMapIndex(paramIndex);

      * RequestHeaderParameterProcessor

获取@RequestHeader注解上的参数且为Map,data.headerMapIndex(parameterIndex);

否则,获取注解上的name值,执行AnnotatedParameterContext.setParameterName(name),会data.indexToName().put(i, names)、data.template().header(name, value);

      * RequestParamParameterProcessor

获取@RequestParam注解上的参数且为Map,data.headerMapIndex(parameterIndex);

否则,获取注解上的name值,执行AnnotatedParameterContext.setParameterName(name),会data.indexToName().put(i, names)、data.template().query(name, value);

value从data.template().queries()获取

- 如果isHttpAnnotation = true && data.indexToExpander().get(paramIndex) == null

获取此参数类型转为字符串的转换器,如果有,设置到indexToExpander


public class SpringMvcContract extends Contract.BaseContractimplements ResourceLoaderAware {

   private static final String ACCEPT = "Accept";
   private static final String CONTENT_TYPE = "Content-Type";
   private static final TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
   private final Map<Class<? extends Annotation>, AnnotatedParameterProcessor> annotatedArgumentProcessors;
   private final Map<String, Method> processedMethods = new HashMap<>();
   private final ConversionService conversionService;
   private final ConvertingExpanderFactory convertingExpanderFactory;
   //

   public SpringMvcContract(List<AnnotatedParameterProcessor> annotatedParameterProcessors,
         ConversionService conversionService) {
      List<AnnotatedParameterProcessor> processors;
      if (!annotatedParameterProcessors.isEmpty()) {
         processors = new ArrayList<>(annotatedParameterProcessors);
      }
      else {
         processors = getDefaultAnnotatedArgumentsProcessors();
      }
      //注解类型和处理器的映射
      this.annotatedArgumentProcessors = toAnnotatedArgumentProcessorMap(processors);
      //这两个是类型转换相关
      this.conversionService = conversionService;
      //借助conversionService把值转为字符串类型
      this.convertingExpanderFactory = new ConvertingExpanderFactory(conversionService);
   }

   //
   @Override
   protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
      if (clz.getInterfaces().length == 0) {
         RequestMapping classAnnotation = findMergedAnnotation(clz,RequestMapping.class);
         if (classAnnotation != null) {
            if (classAnnotation.value().length > 0) {
               String pathValue = emptyToNull(classAnnotation.value()[0]);
               pathValue = resolve(pathValue);
               if (!pathValue.startsWith("/")) {
                  pathValue = "/" + pathValue;
               }
               data.template().uri(pathValue);
            }
         }
      }
   }

   //重写接口核心类
   //1、使用父类parseAndValidateMetadata,这里面也会回调这边的抽象子类实现
   //2、如果存在类上的RequestMapping
   //   - MethodMetadataRequestTemplateACCEPT\CONTENT_TYPE,再解析方法注解后没有设置时,调用parseProducesparseConsumes设置,即使用父类的设置
   //   - 调用parseHeaders设置请求头
   @Override
   public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
      this.processedMethods.put(Feign.configKey(targetType, method), method);
      MethodMetadata md = super.parseAndValidateMetadata(targetType, method);

      RequestMapping classAnnotation = findMergedAnnotation(targetType,RequestMapping.class);
      if (classAnnotation != null) {
         if (!md.template().headers().containsKey(ACCEPT)) {
            parseProduces(md, method, classAnnotation);
         }
         if (!md.template().headers().containsKey(CONTENT_TYPE)) {
            parseConsumes(md, method, classAnnotation);
         }
         parseHeaders(md, method, classAnnotation);
      }
      return md;
   }

   //处理方法上的注解
   //获取RequestMapping注解,取http访问方法(只能有一个),和url(覆盖类上的)
   //parseProduces(data, method, methodMapping,取produces属性作为RequestTemplateACCEP
   //parseConsumes(data, method, methodMapping);consumes属性作为RequestTemplateCONTENT_TYPE
   //parseHeaders(data, method, methodMapping);headers属性作为RequestTemplate的请求头
   @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
      RequestMethod[] methods = methodMapping.method();
      if (methods.length == 0) {
         methods = new RequestMethod[] { RequestMethod.GET };
      }
      checkOne(method, methods, "method");
      data.template().method(Request.HttpMethod.valueOf(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().path().endsWith("/")) {
               pathValue = "/" + pathValue;
            }
            data.template().uri(pathValue, true);
         }
      }

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

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

   private String resolve(String value) {
      if (StringUtils.hasText(value)
            && this.resourceLoader instanceof ConfigurableApplicationContext) {
         return ((ConfigurableApplicationContext) this.resourceLoader).getEnvironment()
               .resolvePlaceholders(value);
      }
      return value;
   }

   //处理参数上的注解
   @Override
   protected boolean processAnnotationsOnParameter(MethodMetadata data,
         Annotation[] annotations, int paramIndex) {
      boolean isHttpAnnotation = false;

      //简单封装了MethodMetadataparameterIndex;
      AnnotatedParameterProcessor.AnnotatedParameterContext context = new SimpleAnnotatedParameterContext(data, paramIndex);
      Method method = this.processedMethods.get(data.configKey());
      //遍历一个参数的所有注解,调用对应的处理类进行处理
      for (Annotation parameterAnnotation : annotations) {
         AnnotatedParameterProcessor processor = this.annotatedArgumentProcessors.get(parameterAnnotation.annotationType());
         if (processor != null) {
            Annotation processParameterAnnotation;
            processParameterAnnotation = synthesizeWithMethodParameterNameAsFallbackValue(
                  parameterAnnotation, method, paramIndex);
            isHttpAnnotation |= processor.processArgument(context,processParameterAnnotation, method);
         }
      }

      //获取此参数类型转为字符串的转换器,如果有,设置到indexToExpander
      if (isHttpAnnotation && data.indexToExpander().get(paramIndex) == null) {
         TypeDescriptor typeDescriptor = createTypeDescriptor(method, paramIndex);
         if (this.conversionService.canConvert(typeDescriptor,STRING_TYPE_DESCRIPTOR)) {
            Param.Expander expander = this.convertingExpanderFactory
                  .getExpander(typeDescriptor);
            if (expander != null) {
               data.indexToExpander().put(paramIndex, expander);
            }
         }
      }
      return isHttpAnnotation;
   }
   
   //
}

5、代理增强SynchronousMethodHandler.invoke

5.1 invoke整体流程

* 基于buildTemplateFromArgs获取RequestTemplate, template = buildTemplateFromArgs.create(实际方法参数);

RequestTemplate里面翻转好了http调用所有的东西,包括访问方法、请求体等

* 获取Options类型的参数、重试器(默认为Retryer.NEVER_RETRY)

* 调用核心方法executeAndDecode(template, options)进行远程调用和响应处理

  ①先执行拦截器遍历调用interceptor.apply(template),是在容器中获取或者配置文件中指定的RequestInterceptor实现类

  ②调用HardCodedTarget(封装了客户端接口类型type、name、url属性).apply方法

- 如果RequestTemplate的url(例如从@RequestMapping获取的)不是以http开头,那么就需要使用HardCodedTarget里的url属性作为此RequestTemplate的host

  RequestTemplate.target(url());,url()表时目标地址,在基于服务name访问时,此值为服务名称,调用target方法会处理RequestTemplate的target属性(拼接好的完整的路径)

- 再调用RequestTemplate.request()返回Request,封装了完整请求相关的信息,包括target + url(完整的或者从@RequestMapping获取的和@feignClient的path)等信息

  ③调用配置的客户端通信组件LoadBalancerFeignClient client.execute获取需要Response (流程见下)

     IClientConfig requestConfig = getClientConfig(options, clientName); //clientName即为域名,服务名

     FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(

this.delegate, request, uriWithoutHost); //this.delegate即为对应委托http客户端

 return lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();

     最终回到FeignLoadBalancer的execute(RibbonRequest request, IClientConfig configOverride)进行通信,执行this.delegate的execute方法返回Response

     此Response包含:int status;

     private final String reason;

     private final Map<String, Collection<String>> headers;

     private final Body body; //响应流

     private final Request request;

  ④处理返回值,默认处理完会关闭响应流,response.body()为网络输入流

- 如果返回值为Response类型,响应体长度超长(8192),直接返回,但是不关闭响应流;

  否则,把响应转为字节数组,封装到一个新的Response(会复制原Response的this.status、reason、headers、body、request;),再返回给客户端

- 如果不为Response类型:code为200~300 :使用decoder对Response进行编码返回,decode(response);

                        code为404且返回类型不为void :使用decoder对Response进行编码返回;根据contentType把响应流的数据转为返回类型即可

                         其他直接抛出异常

  ⑤根据标识,关闭响应流


final class SynchronousMethodHandler implements MethodHandler {

  private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;

  private final MethodMetadata metadata;
  //HardCodedTarget(封装了客户端接口类型typenameurl属性)
  private final Target<?> target;
  //如下组件均从Builder中获取,
  private final Client client;
  private final Retryer retryer;
  private final List<RequestInterceptor> requestInterceptors;
  private final Logger logger;
  private final Logger.Level logLevel;
  private final RequestTemplate.Factory buildTemplateFromArgs;
  private final Options options;
  private final Decoder decoder;
  private final ErrorDecoder errorDecoder;
  private final boolean decode404;
  private final boolean closeAfterDecode;
  private final ExceptionPropagationPolicy propagationPolicy;

  private SynchronousMethodHandler(Target<?> target, Client client, Retryer retryer,
                                   List<RequestInterceptor> requestInterceptors, Logger logger,
                                   Logger.Level logLevel, MethodMetadata metadata,
                                   RequestTemplate.Factory buildTemplateFromArgs, Options options,
                                   Decoder decoder, ErrorDecoder errorDecoder, boolean decode404,
                                   boolean closeAfterDecode, ExceptionPropagationPolicy propagationPolicy) {
    this.target = checkNotNull(target, "target");
    this.client = checkNotNull(client, "client for %s", target);
    this.retryer = checkNotNull(retryer, "retryer for %s", target);
    this.requestInterceptors =
        checkNotNull(requestInterceptors, "requestInterceptors for %s", target);
    this.logger = checkNotNull(logger, "logger for %s", target);
    this.logLevel = checkNotNull(logLevel, "logLevel for %s", target);
    this.metadata = checkNotNull(metadata, "metadata for %s", target);
    this.buildTemplateFromArgs = checkNotNull(buildTemplateFromArgs, "metadata for %s", target);
    this.options = checkNotNull(options, "options for %s", target);
    this.errorDecoder = checkNotNull(errorDecoder, "errorDecoder for %s", target);
    this.decoder = checkNotNull(decoder, "decoder for %s", target);
    this.decode404 = decode404;
    this.closeAfterDecode = closeAfterDecode;
    this.propagationPolicy = propagationPolicy;
  }

  @Override
  public Object invoke(Object[] argv) throws Throwable {
    //获取RequestTemplate,里面翻转好了http调用所有的东西,包括访问方法、请求体等
    RequestTemplate template = buildTemplateFromArgs.create(argv);
    //获取Options类型的参数
    Options options = findOptions(argv);
    //重试器,默认为Retryer.NEVER_RETRY
    Retryer retryer = this.retryer.clone();
    while (true) {
      try {
        //核心方法
        return executeAndDecode(template, options);
      } catch (RetryableException e) {
        try {
          //默认为抛出异常,则会打破循环,无法重试
          retryer.continueOrPropagate(e);
        } catch (RetryableException th) {
          Throwable cause = th.getCause();
          if (propagationPolicy == UNWRAP && cause != null) { throw cause;
          } else {throw th;}
        }
        continue;
      }
    }
  }
  Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
    //先执行拦截器遍历调用interceptor.apply(template)
    //调用HardCodedTarget(封装了客户端接口类型typenameurl属性).apply方法
    //  这里会再次RequestTemplate.target(url()),因为拦截器可以会对url进行修改
    //  再调用RequestTemplate.request()返回Request,封装了请求相关的信息
    Request request = targetRequest(template);
    Response response;
    long start = System.nanoTime();
    try {
      //核心方法:调用配置的客户端通信组件client.execute
      response = client.execute(request, options);
    } catch (IOException e) {
      throw errorExecuting(request, e);
    }

    //处理返回值,默认处理完会关闭响应流
    boolean shouldClose = true;
    try {
      //如果返回值为Response类型,response.body()为网络输入流
      if (Response.class == metadata.returnType()) {
        //响应体长度超长(8192),直接返回,但是不关闭响应流
        if (response.body() == null) {
          return response;
        }
        if (response.body().length() == null || response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
          shouldClose = false;
          return response;
        }
        //把响应转为字节数组,封装到一个新的Response,再返回给客户端
        byte[] bodyData = Util.toByteArray(response.body().asInputStream());
        return response.toBuilder().body(bodyData).build();
      }
      //如果不为Response类型
      // 1code200~300 :使用decoderResponse进行编码返回
      // 2code404且返回类型不为void :使用decoderResponse进行编码返回
      if (response.status() >= 200 && response.status() < 300) {
        if (void.class == metadata.returnType()) {
          return null;
        } else {
          //使用decoderResponse进行编码返回
          Object result = decode(response);
          shouldClose = closeAfterDecode;
          return result;
        }
      } else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
        Object result = decode(response);
        shouldClose = closeAfterDecode;
        return result;
      } else {
        throw errorDecoder.decode(metadata.configKey(), response);
      }
    } catch (IOException e) {
      throw errorReading(request, response, e);
    } finally {
      if (shouldClose) {
        ensureClosed(response.body());
      }
    }
  }

  Request targetRequest(RequestTemplate template) {
    for (RequestInterceptor interceptor : requestInterceptors) {
      interceptor.apply(template);
    }
    return target.apply(template);
  }

  Object decode(Response response) throws Throwable {
    try {
      return decoder.decode(response, metadata.returnType());
    } catch (FeignException e) {
      throw e;
    } catch (RuntimeException e) {
      throw new DecodeException(response.status(), e.getMessage(), response.request(), e);
    }
  }

  Options findOptions(Object[] argv) {
    if (argv == null || argv.length == 0) {
      return this.options;
    }
    return (Options) Stream.of(argv)
        .filter(o -> o instanceof Options)
        .findFirst()
        .orElse(this.options);
  }


}

5.2执行BuildTemplateByResolvingArgs获取RequestTemplate

* 在解析阶段就以及封装好每一个方法对应的BuildTemplateByResolvingArgs或子类

  - 父类BuildTemplateByResolvingArgs

处理解析 RequestTemplate的整体流程,包含大部分的处理,例如对RequestTemplate进行url查询参数(@RequestParam)的拼接、请求头(@RequestHeader)的添加

路径参数的替换

  - 子类BuildFormEncodedTemplateFromArgs

①基于解析阶段的md.bodyIndex(),例如feig接口方法中普通实体类的参数

使用编码器Encoder,默认为SpringEncoder,把bodyIndex对应的参数值转为请求体中contType指定的格式后,写入RequestTemplate的body

②接着执行父类的流程

  - 子类BuildFormEncodedTemplateFromArgs

①从MethodMetadata.indexToName()中获取指定参数的名称和值的集合(包括别名)中过滤metadata.formParams()指定的那些值,封装为Map<String, ?> map

使用编码器Encoder,默认为SpringEncoder,把map转为请求体中contType指定的格式后,写入RequestTemplate的body

②接着执行父类的流程

for (MethodMetadata md : metadata) {
      BuildTemplateByResolvingArgs buildTemplate;
      if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
        buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
      } else if (md.bodyIndex() != null) {
        buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
      } else {
        buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder);
      }
}

* 核心方法时工厂接口方法RequestTemplate create(Object[] argv),返回RequestTemplate

 
interface Factory {
  RequestTemplate create(Object[] argv);
}

* BuildTemplateByResolvingArgs定义工厂的整体实现,create方法

  ①从之前解析的MethodMetadata中RequestTemplate基础上,创建新的RequestTemplate
    会复制MethodMetadata里旧requestTemplate的target、fragment、uriTemplate、method、charset、body、decodeSlash、collectionFormat、queries、headers

②如果参数存在urlIndex,则使用实际参数的URL对象覆盖新RequestTemplate的mutable.target(模板路径)

③变量参数上下文的创建,Map<String, Object> varBuilder,value值会转为String类型

  * 从MethodMetadata.indexToName()中获取指定参数的名称和值的集合(包括别名),使用indexToExpander映射为字符串(如果没有Expande,使用原值),

存到 Map<“名称”, 参数值> varBuilder,

* 这些参数是带有 @PathVariable(value = “名称”)、@RequestHeader(value = “名称”)、@RequestParam(value = “名称”)注解的
  ④底层调用RequestTemplate的resolve(variables)去解析参数值,使用RequestTemplate.resolve(variables),子类可重写

- 先执行子类覆盖的方法返回处理后的参数上下文variables,接着新的RequestTemplate的resolve(variables)方法

- 有基于此新RequestTemplate,在创建一个RequestTemplate副本

- 如果此RequestTemplate的queries查询参数变量不为空,使用参数上下文varBuilder进行表达式赋值,在拼接到url

例如@RequestParam标志的参数,在SpringMvcContract的静态解析阶段就会加入RequestTemplate的queries中,在运行阶段即③会把对应的实际参数值存于varBuilder
    - 如果此的headers不为空,那么处理请求头,使用参数上下文进行表达式赋值,加入到RequestTemplate中

例如@RequestHeader标志的参数,和@RequestParam标志的处理类似处理RequestTemplate的heards中
    - template的bodyTemplate如果存在的话,使用bodyTemplate.expand(variables)获取请求体(BuildEncodedTemplateFromArgs不会走这里)
  ⑤存在@RequestParam(参数类型为Map时)和SpringQueryMap注解时,获取Map对象属性名和值,再存到RequestTemplate的queries中

    在后续的executeAndDecode方法,会把此queries中内容拼接到url上

⑥存在@RequestHeard(参数类型为Map时),获取Map对象属性名和值,存到RequestTemplate的headers

⑦返回此RequestTemplate

* BuildEncodedTemplateFromArgs继承BuildTemplateByResolvingArgs,重写了resolve方法,只增加处理RequestTemplate.body

 ①会使用编码组件SpringEncoder

- 根据请求contenType选择对应的请求编码处理,转为对应的格式后写入存入outputMessage(一个内存输出流中),在把此流数据RequestTemplate的Body中

- 例如时json的请求类型,就会选在messageConverters中选中FastJsonHttpMessageConverter作为转换器把原参数值转为json格式后,

HttpMessageConverter<Object> copy = (HttpMessageConverter<Object>) messageConverter;

copy.write(requestBody, requestContentType, outputMessage);

RequestTemplate.body(Request.Body.encoded(outputMessage.getOutputStream().toByteArray(), charset));//此时的bodyTemplate为null

  ②接着调用父类的super.resolve(argv, mutable, variables)--见上

  

* BuildFormEncodedTemplateFromArgs继承BuildTemplateByResolvingArgs,重写了resolve方法,只增加处理metadata.formParams()

 ①遍历父类传递的variables,如果存于metadata.formParams()中,会使用编码组件SpringEncoder进入处理后,加入RequestTemplate.body

 ②接着调用父类的super.resolve(argv, mutable, variables)--见上

private static class BuildTemplateByResolvingArgs implements RequestTemplate.Factory {

    private final QueryMapEncoder queryMapEncoder;
    protected final MethodMetadata metadata;
    private final Map<Integer, Expander> indexToExpander = new LinkedHashMap<Integer, Expander>();

    private BuildTemplateByResolvingArgs(MethodMetadata metadata, QueryMapEncoder queryMapEncoder) {
      this.metadata = metadata;
      this.queryMapEncoder = queryMapEncoder;
      //indexToExpander收集每个参数值对应的字符转换器
      //代码略
    }

  @Override
  public RequestTemplate create(Object[] argv) {
    //从之前解析的MethodMetadataRequestTemplate基础上,创建新的RequestTemplate
    //会复制旧requestTemplatetargetfragmenturiTemplatemethodcharsetbodydecodeSlashcollectionFormatqueriesheaders
    RequestTemplate mutable = RequestTemplate.from(metadata.template());
    if (metadata.urlIndex() != null) {
      int urlIndex = metadata.urlIndex();
      checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex);
      //创建URI对象,并解析url的参数存到RequestTemplatequeries
      mutable.target(String.valueOf(argv[urlIndex]));
    }
  
    //参数上下文的创建
    // 获取每个参数的名称集合(包括别名)和值,使用indexToExpander映射为字符串,存到 Map<String, Object> varBuilder
    //即对于能够设置别的注解,会在参数值上下文varBuilder中存在副本,比如/PathVariableRequestParamRequestHeader
    Map<String, Object> varBuilder = new LinkedHashMap<String, Object>();
    for (Entry<Integer, Collection<String>> entry : metadata.indexToName().entrySet()) {
      int i = entry.getKey();
      Object value = argv[entry.getKey()];
      if (value != null) { // Null values are skipped.
        if (indexToExpander.containsKey(i)) {
          value = expandElements(indexToExpander.get(i), value);
        }
        for (String name : entry.getValue()) {
          varBuilder.put(name, value);
        }
      }
    }
  
    //底层调用RequestTemplateresolve(variables)去解析参数值,子类可重写,varBuilder存在方法参数和实际值
    //1、处理url上的{}块,使用参数上下文进行表达式赋值
    //2、拼接处理url查询参数queryString,使用参数上下文进行表达式赋值
    //3、处理请求头,使用参数上下文进行表达式赋值
    //4templatebodyTemplate如果存在的话,直接把参数上下文写入请求体
    RequestTemplate template = resolve(argv, mutable, varBuilder);
  
    //存在@RequestParam(参数类型为Map时)和SpringQueryMap注解时,反射获取对象属性名和值拼接到url上,即存到RequestTemplatequeries
    if (metadata.queryMapIndex() != null) {
      Object value = argv[metadata.queryMapIndex()];
      Map<String, Object> queryMap = toQueryMap(value);
      template = addQueryMapQueryParameters(queryMap, template);
    }
  
    //请求头对象的处理,存到RequestTemplateheaders
    if (metadata.headerMapIndex() != null) {
      template =
              addHeaderMapHeaders((Map<String, Object>) argv[metadata.headerMapIndex()], template);
    }
  
    return template;
  }

}

//只重写resolve方法
private static class BuildEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs {

    private final Encoder encoder;

    private BuildEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder,
        QueryMapEncoder queryMapEncoder) {
      super(metadata, queryMapEncoder);
      this.encoder = encoder;
    }
    @Override
    protected RequestTemplate resolve(Object[] argv,RequestTemplate mutable,Map<String, Object> variables) {
      Object body = argv[metadata.bodyIndex()];
      checkArgument(body != null, "Body parameter %s was null", metadata.bodyIndex());
      try {
        encoder.encode(body, metadata.bodyType(), mutable);
      } catch (EncodeException e) {
        throw e;
      } catch (RuntimeException e) {
        throw new EncodeException(e.getMessage(), e);
      }
      return super.resolve(argv, mutable, variables);
    }
  }
}

5.3 执行LoadBalancerFeignClient.execute进行负载均衡调用

5.3.1 概述

* Feign顶级接口Client

public interface Client {
      Response execute(Request request, Options options) throws IOException;

}

* LoadBalancerFeignClient

顶层Client组件实现,在每一个单独name容器里是没有配置的,而存在于其父容器(Spring容器)中,

默认为LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);,其中参数均是从父容器注入,在 FeignRibbonClientAutoConfiguration中

①delegate为:内部委托的时机通信对象,比如ApacheHttpClient(也是顶层Client接口实现),适配底层的HttpClient(CloseableHttpClient)接口的实现类

②cachingFactory, clientFactory:创建Ribbon的工厂,见Spring Ribbon原理

* execute方法的实现流程

 ①从RequestTamplate中获取的Request中,创建URL,获取域名为服务名称,会基于此服务名称创建Ribbon的上下文

 ②从Ribbon工厂lbClientFactory中clientFactory获取IClientConfig,lbClient(clientName会调用lbClientFactory.create(clientName);

   会创建org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer对象,这里就兼容了ribbon的功能了

 ③调用FeignLoadBalancer的executeWithLoadBalancer方法进行负载均衡且通信,获取响应对象Response返回

   

public class LoadBalancerFeignClient implements Client {

   static final Request.Options DEFAULT_OPTIONS = new Request.Options();
    //内部委托的时机通信对象,如okHttpClient
   private final Client delegate;
    //创建Ribbon的工厂
   private CachingSpringLoadBalancerFactory lbClientFactory;
   private SpringClientFactory clientFactory;

   public LoadBalancerFeignClient(Client delegate,
                                   CachingSpringLoadBalancerFactory lbClientFactory,
                                   SpringClientFactory clientFactory) {
      this.delegate = delegate;
      this.lbClientFactory = lbClientFactory;
      this.clientFactory = clientFactory;
   }
   
   @Override
   public Response execute(Request request, Request.Options options) throws IOException {
      try {
         //创建URL,获取域名为服务名称,会基于此服务名称创建Ribbon的上下文
         URI asUri = URI.create(request.url());
         String clientName = asUri.getHost();
         URI uriWithoutHost = cleanUrl(request.url(), clientName);
         FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
               this.delegate, request, uriWithoutHost);

         //Ribbon工厂中clientFactory获取IClientConfig
         IClientConfig requestConfig = getClientConfig(options, clientName);
         //通过SpringClientFactory创建基于Ribbon负载均衡的客户端FeignLoadBalancer,调用其executeWithLoadBalancer方法后获取响应对象Response
         return lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
      }
      catch (ClientException e) {
         throw new RuntimeException(e);
      }
   }

   IClientConfig getClientConfig(Request.Options options, String clientName) {
      IClientConfig requestConfig;
      if (options == DEFAULT_OPTIONS) {
         requestConfig = this.clientFactory.getClientConfig(clientName);
      }
      else {
         requestConfig = new FeignOptionsClientConfig(options);
      }
      return requestConfig;
   }
   private FeignLoadBalancer lbClient(String clientName) {
      return this.lbClientFactory.create(clientName);
   }

   //
}

     

5.3.2 FeignLoadBalance的创建

* LoadBalancerContext

  底层封装了ILoadBalancer,主要提供例如基于ILoadBalancer选择服务实例方法、暴露记录服务状态的方法

* 基于SpringClientFactory 工厂创建FeignLoadBalancer

- SpringClientFactory是创建ribbon负载均衡功能的工厂,可以为当前clientName创建单独容器上下文,

可以获取ribbon的几个组件IClientConfig、IRule、IPing、ServerList<Server>、ServerListFilter<Server>、ILoadBalancer(Ribbon原理见上)

  - 从Ribbon工厂中获取到IClientConfig、ILoadBalancer、ServerIntrospector后作为构造参数创建FeignLoadBalancer对象

    new FeignLoadBalancer(ILoadBalancer , config, serverIntrospector),其中ILoadBalancer 的默认实现即为ZoneAwareLoadBalancer

public class CachingSpringLoadBalancerFactory {

   protected final SpringClientFactory factory;
   protected LoadBalancedRetryFactory loadBalancedRetryFactory = null;

   private volatile Map<String, FeignLoadBalancer> cache = new ConcurrentReferenceHashMap<>();
   public CachingSpringLoadBalancerFactory(SpringClientFactory factory) {
      this.factory = factory;
   }
   public CachingSpringLoadBalancerFactory(SpringClientFactory factory,
         LoadBalancedRetryFactory loadBalancedRetryPolicyFactory) {
      this.factory = factory;
      this.loadBalancedRetryFactory = loadBalancedRetryPolicyFactory;
   }


   public FeignLoadBalancer create(String clientName) {
      FeignLoadBalancer client = this.cache.get(clientName);
      if (client != null) {
         return client;
      }
      IClientConfig config = this.factory.getClientConfig(clientName);
      ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
      ServerIntrospector serverIntrospector = this.factory.getInstance(clientName,
            ServerIntrospector.class);
      client = this.loadBalancedRetryFactory != null
            ? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
                  this.loadBalancedRetryFactory)
            : new FeignLoadBalancer(lb, config, serverIntrospector);
      this.cache.put(clientName, client);
      return client;
   }

}

5.3.3 FeignLoadBalance的executeWithLoadBalancer执行请求

基于LoadBalancerCommand实现这个流程:

* buildLoadBalancerComman方法:先创建LoadBalancerCommand,

①配置好LoadBalancerContext、RetryHandler、url

②其中RetryHandler会抽象子类实现:getRequestSpecificRetryHandler定制重试处理器获取

③使用抽象子类customizeLoadBalancerCommandBuilder定制customizeLoadBalancerCommandBuilder构造

④执行build进行创建LoadBalancerCommand

* 调用LoadBalancerCommand.submit处理整个流程,基于Observable

①触发ExecutionContextListenerInvoker监听器启动事件

②调用getServerFromLoadBalancer获取负载均衡后的服务实例(此方法封装于父类)

  基于ILoadBalancer.chooseServer选择FeignLoadBalance

③再调用IClient接口的execute方法,例如FeignLoadBalance会实现这个方法

- 如果Feign配置了自己的超时时间,则优先时间,否则使用Ribbon配置的,存于IClientConfig中,

- 调用RibbonRequest.client()获取底层委托的HttpClient(从LoadBalancerFeignClient获取)的execute方法

- 返回响应RibbonResponse

④如果访问有异常,会基于retryHandler进行重试处,超过重试次数之后,直接抛出

  注:调用流程的每个重要结点,例如请求完成后会调用LoadBalancerContext.noteRequestCompletion,会更新ILoadBalancer中服务的访问状态

//AbstractLoadBalancerAwareClient

   public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
       //创建LoadBalancerCommand
       //①配置好LoadBalancerContextRetryHandlerurl、手动指定Server
       //②会暴露两个方法给子类实现:getRequestSpecificRetryHandler定制重试处理器、customizeLoadBalancerCommandBuilder定制customizeLoadBalancerCommandBuilder
       LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);

       //开始进行负载均衡、和远程调用
       try {
           return command.submit(
               new ServerOperation<T>() {
                   @Override
                   public Observable<T> call(Server server) {
                       URI finalUri = reconstructURIWithServer(server, request.getUri());
                       S requestForServer = (S) request.replaceUri(finalUri);
                       try {
                           //调用子类的execute,如FeignLoadBalancer的实现时,先优先使用Feign的超时功能,在调用底层委托的HttpCClient.execute
                           return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
                       }
                       catch (Exception e) { return Observable.error(e);}
                   }
               })
               .toBlocking()
               .single();
       } catch (Exception e) {
           Throwable t = e.getCause();
           if (t instanceof ClientException) {throw (ClientException) t;
           } else {throw new ClientException(e);}
       }
       
   }
   
   public abstract RequestSpecificRetryHandler getRequestSpecificRetryHandler(S request, IClientConfig requestConfig);

  protected LoadBalancerCommand<T> buildLoadBalancerCommand(final S request, final IClientConfig config) {
    RequestSpecificRetryHandler handler = getRequestSpecificRetryHandler(request, config);
    LoadBalancerCommand.Builder<T> builder = LoadBalancerCommand.<T>builder()
          .withLoadBalancerContext(this)
          .withRetryHandler(handler)
          .withLoadBalancerURI(request.getUri());
    customizeLoadBalancerCommandBuilder(request, config, builder);
   return builder.build();
}

//LoadBalancerCommand

public Observable<T> submit(final ServerOperation<T> operation) {
    //创建此次请求的执行上下文,封装了ServerserverAttemptCountattemptCount = 0;
    final ExecutionInfoContext context = new ExecutionInfoContext();

    //监听器的触发
    if (listenerInvoker != null) {
        try {
            listenerInvoker.onExecutionStart();
        } catch (AbortExecutionException e) {
            return Observable.error(e);
        }
    }

    final int maxRetrysSame = retryHandler.getMaxRetriesOnSameServer();
    final int maxRetrysNext = retryHandler.getMaxRetriesOnNextServer();

    //selectServer方法:getServerFromLoadBalancer获取负载均衡后的服务实例(此方法封装于父类)
    //                  基于ILoadBalancer.chooseServer选择FeignLoadBalance
    Observable<T> o =
            (server == null ? selectServer() : Observable.just(server))
            .concatMap(new Func1<Server, Observable<T>>() {
                @Override
                //修改IloadBalancer中此选定服务实例的状态,比如请求访问数、成功|失败数等
                public Observable<T> call(Server server) {
                    context.setServer(server);
                    final ServerStats stats = loadBalancerContext.getServerStats(server);
                    
                    // Called for each attempt and retry
                    Observable<T> o = Observable
                            .just(server)
                            .concatMap(new Func1<Server, Observable<T>>() {
                                @Override
                                public Observable<T> call(final Server server) {
                                    context.incAttemptCount();
                                    loadBalancerContext.noteOpenConnection(stats);
                                    
                                    if (listenerInvoker != null) {
                                        try {
                                            listenerInvoker.onStartWithServer(context.toExecutionInfo());
                                        } catch (AbortExecutionException e) {
                                            return Observable.error(e);
                                        }
                                    }
                                    
                                    final Stopwatch tracer = loadBalancerContext.getExecuteTracer().start();

                                    //这里调用传递进来的operation,是执行对服务实例接口的访问,每个结点会记录服务实例的状态
                                    return operation.call(server).doOnEach(new Observer<T>() {
                                        private T entity;
                                        @Override
                                        public void onCompleted() {
                                            recordStats(tracer, stats, entity, null);
                                        }

                                        @Override
                                        public void onError(Throwable e) {
                                            recordStats(tracer, stats, null, e);
                                            if (listenerInvoker != null) {
                                                listenerInvoker.onExceptionWithServer(e, context.toExecutionInfo());
                                            }
                                        }
                                        @Override
                                        public void onNext(T entity) {
                                            this.entity = entity;
                                            if (listenerInvoker != null) {
                                                listenerInvoker.onExecutionSuccess(entity, context.toExecutionInfo());
                                            }
                                        }                            
                                        
                                        private void recordStats(Stopwatch tracer, ServerStats stats, Object entity, Throwable exception) {
                                            tracer.stop();
                                            loadBalancerContext.noteRequestCompletion(stats, entity, exception, tracer.getDuration(TimeUnit.MILLISECONDS), retryHandler);
                                        }
                                    });
                                }
                            });

                    //如果出现异常,进行重试处理,FeignLoadBalance是默认不进行重试
                    if (maxRetrysSame > 0)
                        o = o.retry(retryPolicy(maxRetrysSame, true));
                    return o;
                }
            });
        
    if (maxRetrysNext > 0 && server == null)
        o = o.retry(retryPolicy(maxRetrysNext, false));

    //重试还是异常的话,就抛出
    return o.onErrorResumeNext(new Func1<Throwable, Observable<T>>() {
        @Override
        public Observable<T> call(Throwable e) {
            if (listenerInvoker != null) {
                listenerInvoker.onExecutionFailed(e, context.toFinalExecutionInfo());
            }
            return Observable.error(e);
        }
    });
}

5.3.4 FeignLoadBalance对重试处理的实现

* 创建RequestSpecificRetryHandle时,赋值给父类LoadBalancerContext的retryHandler变量

①若为非GET请求,okToRetryOnAllErrors为false

②其他情况一样:okToRetryOnConnectErrors为true、okToRetryOnAllErrors为true、retrySameServer取MaxAutoRetries、retryNextServer 取MaxAutoRetriesNextServer

* 在submit时

  ①如果已经获取到服务实例server,访问发送异常时判断retrySameServer大于0,会进行重试

  ②如果没有获取到服务实例server,发送异常时判断retryNextServer 大于0,会进行重试

@Override
public RequestSpecificRetryHandler getRequestSpecificRetryHandler(
      RibbonRequest request, IClientConfig requestConfig) {
   if (this.ribbon.isOkToRetryOnAllOperations()) {
      return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),requestConfig);
   }
   if (!request.toRequest().httpMethod().name().equals("GET")) {
      return new RequestSpecificRetryHandler(true, false, this.getRetryHandler(),requestConfig);
   }
   else {
      return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),requestConfig);
   }
}

public RequestSpecificRetryHandler(boolean okToRetryOnConnectErrors, boolean okToRetryOnAllErrors, RetryHandler baseRetryHandler, @Nullable IClientConfig requestConfig) {
    Preconditions.checkNotNull(baseRetryHandler);
    this.okToRetryOnConnectErrors = okToRetryOnConnectErrors;
    this.okToRetryOnAllErrors = okToRetryOnAllErrors;
    this.fallback = baseRetryHandler;
    if (requestConfig != null) {
        if (requestConfig.containsProperty(CommonClientConfigKey.MaxAutoRetries)) {
            retrySameServer = requestConfig.get(CommonClientConfigKey.MaxAutoRetries);
        }
        if (requestConfig.containsProperty(CommonClientConfigKey.MaxAutoRetriesNextServer)) {
            retryNextServer = requestConfig.get(CommonClientConfigKey.MaxAutoRetriesNextServer);
        }
    }
}

6、feign整合Hystrix

6.1 配置

  高版本的,需要如下配置,原先的feign.hystrix.enabled无效

* 配置

feign.circuitbreaker.enabled = true

* pom新增依赖

 以新增CiruitBreaker实现类

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
 </dependency>

* 使用如下配置

hystrix:

  command:

    default:

      metrics:

        rollingStats:

          timeInMilliseconds: 5000

      circuitBreaker:

        requestVolumeThreshold: 2

        errorThresholdPercentage: 50

        sleepWindowInMilliseconds: 10000

6.2 源码

6.2.1 自动配置

 Spring Cloud OpenFeign 配置之一 feign.circuitbreaker.enabled=true 开启 CircuitBreaker。直接看 feign 的配置类 FeignClientsConfiguration。

 自动配置支持Hystrix的:

 * Builder:FeignCircuitBreaker.builder()

 * Target:  FeignCircuitBreakerTarget,会封装好如下的CircuitBreakerFactory

 * CircuitBreakerFactory实现类:HsytrixCircuitBreakerFactory,在spring-cloud-starter-netflix-hystrix新版本中

public class FeignClientsConfiguration {

......

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(CircuitBreaker.class)
    @ConditionalOnProperty("feign.circuitbreaker.enabled")
    protected static class CircuitBreakerPresentFeignBuilderConfiguration {

        @Bean
        @Scope("prototype")
        @ConditionalOnMissingBean({ Feign.Builder.class, CircuitBreakerFactory.class })
        public Feign.Builder defaultFeignBuilder(Retryer retryer) {
            return Feign.builder().retryer(retryer);
        }

        @Bean
        @Scope("prototype")
        @ConditionalOnMissingBean
        @ConditionalOnBean(CircuitBreakerFactory.class)
        public Feign.Builder circuitBreakerFeignBuilder() {
            return FeignCircuitBreaker.builder();
        }

    }

......

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Hystrix.class })
@ConditionalOnProperty(name = "spring.cloud.circuitbreaker.hystrix.enabled",
      matchIfMissing = true)
public class HystrixCircuitBreakerAutoConfiguration {

   @Bean
   @ConditionalOnMissingBean(CircuitBreakerFactory.class)
   public CircuitBreakerFactory hystrixCircuitBreakerFactory() {
      return new HystrixCircuitBreakerFactory();
   }

  .....

}

6.2.2 使用FeignCircuitBreake.Builder和target方法创建ReflectiveFeign

* 使用FeignCircuitBreaker.Builder收集配置的组件,他是Feign.Builder的子类

  与常规的Targete相比,这个其中可以会指定FallbackFactory或者fallback

* 使用FeignCircuitBreakerTargete的target方法

  - 如果配置FallbackFactory或者fallback,那么会使用FeignCircuitBreakerInvocationHandler覆盖Builder的invocationHandlerFactory (默认为InvocationHandlerFactory.Default()),

  - 其中cretate的实现就是返回一个FeignCircuitBreakerInvocationHandler(默认的是返回FeignInvocationHandler)

super.invocationHandlerFactory((target, dispatch) -> new FeignCircuitBreakerInvocationHandler(

                    circuitBreakerFactory, feignClientName, target, dispatch, nullableFallbackFactory,

                    circuitBreakerGroupEnabled, circuitBreakerNameResolver));

* 调用Builder的newInstance生成ReflectiveFeign。

  和常规的ReflectiveFeign相比,只是其中的InvocationHandlerFactory不一样,即代理增强不一样。

class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
   
   ......

   @Override
   public Object getObject() throws Exception {
      return getTarget();
   }
   <T> T getTarget() {
      ......

         return (T) loadBalance(builder, context,
               new HardCodedTarget<>(this.type, this.name, this.url));
      }
      ......

   }
   
   
   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);
      }

   }

class FeignCircuitBreakerTargeter implements Targeter {
    private final Map<String,Method> map = new HashMap<>();
    private final CircuitBreakerFactory circuitBreakerFactory;
    private final boolean circuitBreakerGroupEnabled;
    private final CircuitBreakerNameResolver circuitBreakerNameResolver;


    FeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, boolean circuitBreakerGroupEnabled, CircuitBreakerNameResolver circuitBreakerNameResolver) {
        this.circuitBreakerFactory = circuitBreakerFactory;
        this.circuitBreakerGroupEnabled = circuitBreakerGroupEnabled;
        this.circuitBreakerNameResolver = circuitBreakerNameResolver;
        for (Method method : ReflectionUtils.getDeclaredMethods(FeignCircuitBreaker.Builder.class)) {
            map.put(method.getName(),method);
        }
    }

    @Override
    public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
                        Target.HardCodedTarget<T> target) {
        if (!(feign instanceof FeignCircuitBreaker.Builder)) {
            return feign.target(target);
        }
        FeignCircuitBreaker.Builder builder = (FeignCircuitBreaker.Builder) feign;
        String name = !StringUtils.hasText(factory.getContextId()) ? factory.getName() : factory.getContextId();
        Class<?> fallback = factory.getFallback();
        if (fallback != void.class) {
            return targetWithFallback(name, context, target, builder, fallback);
        }
        Class<?> fallbackFactory = factory.getFallbackFactory();
        if (fallbackFactory != void.class) {
            //获取指定的FallbackFactory,断路器工厂HsytrixCircuitBreakerFactory,最终创建ReflectiveFeign
            return targetWithFallbackFactory(name, context, target, builder, fallbackFactory);
        }
        return builder(name, builder).target(target,new GlobalFallBackFactory<>(target));
    }

    private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
                                            Target.HardCodedTarget<T> target, FeignCircuitBreaker.Builder builder, Class<?> fallbackFactoryClass) {
        FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext("fallbackFactory",
                feignClientName, context, fallbackFactoryClass, FallbackFactory.class);

//在FeignCircuitBreaker.Builder中设置下feignClientName和circuitBreakerFactory(容器中获取)

//最终创建ReflectiveFeign,其内设置 invocationHandlerFactory  FeignCircuitBreakerInvocationHandler
        return builder(feignClientName, builder).target(target, fallbackFactory);
    }

    private <T> T targetWithFallback(String feignClientName, FeignContext context, Target.HardCodedTarget<T> target,
                                     FeignCircuitBreaker.Builder builder, Class<?> fallback) {
        T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());
        return builder(feignClientName, builder).target(target, fallbackInstance);
    }

    //


}

//重点在其Builder实现类

public final class FeignCircuitBreaker {

    ......

    public static final class Builder extends Feign.Builder {

    ......

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

@Override
        public <T> T target(Target<T> target,FallbackFactory<?> fallbackFactory) {
            return build(fallbackFactory).newInstance(target);
        }

        public Feign build(final FallbackFactory<?> nullableFallbackFactory) {
            // 设置 invocationHandlerFactory  FeignCircuitBreakerInvocationHandler
            super.invocationHandlerFactory((target, dispatch) -> new FeignCircuitBreakerInvocationHandler(
                    circuitBreakerFactory, feignClientName, target, dispatch, nullableFallbackFactory,
                    circuitBreakerGroupEnabled, circuitBreakerNameResolver));
            return super.build();
        }

    }
}

6.2.3 使用FeignCircuitBreakerInvocationHandler创建Hystrix增强类

* 创建时机

  - 在FeignCircuitBreakerTargeter的target方法创建代理中,就这种了代理增强类为FeignCircuitBreakerInvocationHandler

  - 其中核心参数:

①target代理接口、dispatch为Map<String, MethodHandler>

②circuitBreakerFactory,由容器中获取,nullableFallbackFactory默认为null


super.invocationHandlerFactory((target, dispatch) -> new FeignCircuitBreakerInvocationHandler(
      circuitBreakerFactory, feignClientName, target, dispatch, nullableFallbackFactory,
      circuitBreakerGroupEnabled, circuitBreakerNameResolver));

* 增强的逻辑:

- 通过circuitBreakerNameResolver解析 feign 单个方法的keyName

比如Hystrx下的话,会是: 类名#方法名(参数类型)

- 通过获取CircuitBreaker工厂CircuitBreaker实例(见下节)

    可通过HsytrixCircuitBreakerFactory.create(keyName)获取支持Hsytrix功能的CircuitBreaker

- 构建 circuitBreaker 执行的 supplier,里面封装了目标执行方法

    里面执行的时: (Map<String, MethodHandler>)dispatch.get(method).invoke(args);

- 使用CircuitBreaker执行这个supplier

①nullableFallbackFactory不为null时,会生成函数对象fallback,届时会回调此fallback方法,执行CircuitBreaker.run(supplier,fallback)

  即我们在@FeignClient中配置了fallback/fallbackFactory的情况会走此步骤

②nullableFallbackFactory为null时,直接CircuitBreaker.run(supplier)

public class ReflectiveFeign extends Feign {

    //...
    
    @Override
    public <T> T newInstance(Target<T> target) {
        Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
        Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
        List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();

        //...
        
        //使用FeignCircuitBreakerInvocationHandler来创建Hystri支持的增强类
        InvocationHandler handler = factory.create(target, methodToHandler);
        T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
                new Class<?>[] {target.type()}, handler);

        for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
            defaultMethodHandler.bindTo(proxy);
        }
        return proxy;
    }

    //...

}

class FeignCircuitBreakerInvocationHandler implements InvocationHandler {
    ......

    @Override
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
        ......

        // 解析 feign 当个方法key 类名#方法名(参数类型)
        String circuitName = circuitBreakerNameResolver.resolveCircuitBreakerName(feignClientName, target, method);
        // 通过获取CircuitBreaker工厂CircuitBreaker实例
        // 可通过HsytrixCircuitBreakerFactory获取支持Hsytrix功能的CircuitBreaker
        CircuitBreaker circuitBreaker = circuitBreakerGroupEnabled ? factory.create(circuitName, feignClientName)
                : factory.create(circuitName);
        // 构建 circuitBreaker 执行的 supplier,里面封装了目标执行方法
        Supplier<Object> supplier = asSupplier(method, args);
        // 设置 fallback
        if (this.nullableFallbackFactory != null) {
            Function<Throwable, Object> fallbackFunction = throwable -> {
                Object fallback = this.nullableFallbackFactory.create(throwable);
                try {
                    return this.fallbackMethodMap.get(method).invoke(fallback, args);
                }
                catch (Exception e) {
                    throw new IllegalStateException(e);
                }
            };

            // 通过CircuitBreaker执行带有 fallback  supplier
            return circuitBreaker.run(supplier, fallbackFunction);
        }

        // 执行 supplier
        return circuitBreaker.run(supplier);
    }

    private Supplier<Object> asSupplier(final Method method, final Object[] args) {
        // circuitBreaker 运行的时候会在另一个线程中,所以切换线程的时候同时切换上下文信息
        final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        return () -> {
            try {
                RequestContextHolder.setRequestAttributes(requestAttributes);
                return dispatch.get(method).invoke(args);
            }
            catch (RuntimeException throwable) {
                throw throwable;
            }
            catch (Throwable throwable) {
                throw new RuntimeException(throwable);
            }
        };
    }
    ......

}

6.2.4 CircuitBreakerFactory工厂

6.2.4.1 AbstractCircuitBreakerFactory抽象类

* CircuitBreakerFactory抽象类

  - 有两种:阻塞的和响应的

  - create方法:用于返回具体的CircuitBreaker实现类,这时为了用户选择需要的熔断实现

比如resilience4j和Hystrix熔断,这里举例HystrixCircuitBreaker的

// 阻塞的
public abstract class CircuitBreakerFactory<CONF, CONFB extends ConfigBuilder<CONF>>
        extends AbstractCircuitBreakerFactory<CONF, CONFB> {
    public abstract CircuitBreaker create(String id);
    public CircuitBreaker create(String id, String groupName) {
        return create(id);
    }
}

// reactive
public abstract class ReactiveCircuitBreakerFactory<CONF, CONFB extends ConfigBuilder<CONF>>
        extends AbstractCircuitBreakerFactory<CONF, CONFB> {
    public abstract ReactiveCircuitBreaker create(String id);
    public ReactiveCircuitBreaker create(String id, String groupName) {
        return create(id);
    }
}

6.2.4.2 HystrixCircuitBreakerFactory实现类

* HystrixCommand.Setter配置setter的处理

  - 可以通过工厂的configure方法基于Builder进行自定义配置。可以配置GroupKey、CommandKey、CommandPropertiesDefaults三个

  - 如果没有局部的自定义,那么使用默认defaultConfiguration作为,这里也是需要通过工厂进行指定

如果没有指定,最终取默认配置:只有GroupKey = 类名 ,CommandKey为类名#方法名(参数类型)

* 核心方法create实现

  直接new HystrixCircuitBreaker(setter);

public class HystrixCircuitBreakerFactory extends
        CircuitBreakerFactory<HystrixCommand.Setter, org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerFactory.HystrixConfigBuilder> {

    private Function<String, HystrixCommand.Setter> defaultConfiguration = id -> HystrixCommand.Setter
            .withGroupKey(
                    HystrixCommandGroupKey.Factory.asKey(getClass().getSimpleName()))
            .andCommandKey(HystrixCommandKey.Factory.asKey(id));

    //配置全局默认的HystrixCommand.Setter
    public void configureDefault(
            Function<String, HystrixCommand.Setter> defaultConfiguration) {
        this.defaultConfiguration = defaultConfiguration;
    }

    public HystrixConfigBuilder configBuilder(String id) {
        return new HystrixCircuitBreakerFactory.HystrixConfigBuilder(id);
    }

    //用户可以调用工厂父类的configure,指定指定id设置自定义的HystrixCommand.Setter
    //      此方法还会回调configBuilder方法。这里有内部实现类HystrixConfigBuilder
    //没有就默认为defaultConfiguration。可通过configureDefault进行配置全局默认的HystrixCommand.Setter
    public HystrixCircuitBreaker create(String id) {
        HystrixCommand.Setter setter = getConfigurations().computeIfAbsent(id,
                defaultConfiguration);
        return new HystrixCircuitBreaker(setter);
    }

    public static class HystrixConfigBuilder
            extends AbstractHystrixConfigBuilder<HystrixCommand.Setter> {

        public HystrixConfigBuilder(String id) {
            super(id);
        }

        @Override
        public HystrixCommand.Setter build() {
            return HystrixCommand.Setter.withGroupKey(getGroupKey())
                    .andCommandKey(getCommandKey())
                    .andCommandPropertiesDefaults(getCommandPropertiesSetter());
        }

    }

}

6.2.4.3 HystrixCircuitBreaker 实现类

public interface CircuitBreaker {

   default <T> T run(Supplier<T> toRun) {
      return run(toRun, throwable -> {
         throw new NoFallbackAvailableException("No fallback available.", throwable);
      });
   };
   <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback);

}

* 通过HystrixCommand封装好配置类HystrixCommand.Setter,进行调用就可

* 其中实现run()为目标方法的调用

  - HystrixCommand的run():调用就是原(Map<String, MethodHandler>)dispatch.get(method).invoke(args);

  - HystrixCommand的getFallback():调用的就是封装了用户指定的fallbackFactory的apply方法

public class HystrixCircuitBreaker implements CircuitBreaker {

   private HystrixCommand.Setter setter;

   public HystrixCircuitBreaker(HystrixCommand.Setter setter) {
      this.setter = setter;
   }

   @Override
   public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) {

      HystrixCommand<T> command = new HystrixCommand<T>(setter) {
         @Override
         protected T run() throws Exception {
            return toRun.get();
         }

         @Override
         protected T getFallback() {
            return fallback.apply(getExecutionException());
         }
      };
      return command.execute();
   }

}

public abstract class HystrixCommand<R> extends AbstractCommand<R> implements HystrixExecutable<R>, HystrixInvokableInfo<R>, HystrixObservable<R> {

    protected HystrixCommand(Setter setter) {
        // use 'null' to specify use the default
        this(setter.groupKey, setter.commandKey, setter.threadPoolKey, null, null, setter.commandPropertiesDefaults, setter.threadPoolPropertiesDefaults, null, null, null, null, null);
    }

    protected AbstractCommand(HystrixCommandGroupKey group, HystrixCommandKey key, HystrixThreadPoolKey threadPoolKey, HystrixCircuitBreaker circuitBreaker, HystrixThreadPool threadPool,
                              HystrixCommandProperties.Setter commandPropertiesDefaults, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults,
                              HystrixCommandMetrics metrics, TryableSemaphore fallbackSemaphore, TryableSemaphore executionSemaphore,
                              HystrixPropertiesStrategy propertiesStrategy, HystrixCommandExecutionHook executionHook) {

        this.commandGroup = initGroupKey(group);
        this.commandKey = initCommandKey(key, getClass());
        //这里会从配置文件(远程)中获得相关的配置信息
        this.properties = initCommandProperties(this.commandKey, propertiesStrategy, commandPropertiesDefaults);
        this.threadPoolKey = initThreadPoolKey(threadPoolKey, this.commandGroup, this.properties.executionIsolationThreadPoolKeyOverride().get());
        this.metrics = initMetrics(metrics, this.commandGroup, this.threadPoolKey, this.commandKey, this.properties);
        this.circuitBreaker = initCircuitBreaker(this.properties.circuitBreakerEnabled().get(), circuitBreaker, this.commandGroup, this.commandKey, this.properties, this.metrics);
        this.threadPool = initThreadPool(threadPool, this.threadPoolKey, threadPoolPropertiesDefaults);

        //
    }

   //
}

更多推荐