minjay26
敬畏每一行代码

     spring cloud feign我们使用 @FeignClient注解,其中有几个核心属性:

@AliasFor("name")
String value() default "";

@Deprecated
String serviceId() default "";

/**
 * This will be used as the bean name instead of name if present, but will not be used as a service id.这个注释我理解的似乎有点问题,不知道理解的对不对
 */
String contextId() default "";

@AliasFor("value")
String name() default "";

String qualifier() default "";

  

spring会用FeignClientsRegistrar这个类注册当前client,其中有一个很重要的属性就是clientName,因为clientName会影响到我们配置该client,clientName的定义看下面代码,可以看到contextId的优先级最高,当你定义了contextId后clientName取的就是contextId。


org.springframework.cloud.openfeign.FeignClientsRegistrar.getClientName
private String getClientName(Map<String, Object> client) {
   if (client == null) {
      return null;
   }
   String value = (String) client.get("contextId");//可以看到contextId的优先级最高>value>name>serviceId
   if (!StringUtils.hasText(value)) {
      value = (String) client.get("value");
   }
   if (!StringUtils.hasText(value)) {
      value = (String) client.get("name");
   }
   if (!StringUtils.hasText(value)) {
      value = (String) client.get("serviceId");
   }
   if (StringUtils.hasText(value)) {
      return value;
   }

   throw new IllegalStateException("Either 'name' or 'value' must be provided in @"
         + FeignClient.class.getSimpleName());
}

其中有一个很容易搞错的问题,就是client beanName(区别于clientName),首先看出qualifier的级别最高,如果没有定义qualifier但定义了contextId后实际的bean名称是contextId+"FeignClient"


org.springframework.cloud.openfeign.FeignClientsRegistrar.registerFeignClient
String alias = contextId + "FeignClient";//拼接了FeignClient
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();

boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null

beanDefinition.setPrimary(primary);

String qualifier = getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {//如果有qualifier就用qualifier
   alias = qualifier;
}

但是FeignClient注解contextId源码中的注释 This will be used as the bean name instead of name if present, but will not be used as a service id.我理解起来这个注释有点问题 

 

spring cloud feign的配置都是基于clientName来识别的,例如

   feign.client.clientName.connect-timeout=100

相关配置会被装载到FeignClientProperties,其中支持配置的属性如图

 

 最终通过FeignClientFactoryBean将FeignClientProperties中相应client的配置装配到feignclient中,核心方法为

 

org.springframework.cloud.openfeign.FeignClientFactoryBean.configureFeign

protected void configureFeign(FeignContext context, Feign.Builder builder) {
   FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
   if (properties != null) {
      if (properties.isDefaultToProperties()) {
          //三种配置依次装载
         configureUsingConfiguration(context, builder);//先配置Java代码中的配置
         configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);//配置文件中的默认配置
         configureUsingProperties(properties.getConfig().get(this.contextId), builder);//配置了clientName的配置
      } else {
         configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
         configureUsingProperties(properties.getConfig().get(this.contextId), builder);
         configureUsingConfiguration(context, builder);
      }
   } else {
      configureUsingConfiguration(context, builder);
   }
}

 

  

 

 
posted on 2021-12-29 19:26  minjay26  阅读(430)  评论(0编辑  收藏  举报