Spring Cloud Feign源碼解析

咱們知道要使用feign,須要在springboot啓動類放入@EnableFeignClients開關來打開feign的使用。java

@EnableFeignClients
@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {

   public static void main(String[] args) {
      SpringApplication.run(GatewayApplication.class, args);
   }

}

而後會使用例如spring

@FeignClient("user-center")
public interface UserClient {
    @PostMapping("/users-anon/finduser")
    LoginAppUser findUserByName(@RequestParam("username") String username);
}

如今咱們能夠考慮的方向是打上了@FeignClient("user-center")標籤後,UserClient接口是如何被實例化成對象的,而後是在Controller中調用UserClient對象是如何進行網絡請求的。數組

@Slf4j
@RestController
public class TokenController {

    @Autowired
    private Oauth2Client oauth2Client;
    @Autowired
    private UserClient userClient;


    /**
     * 系統登錄<br>
     * 根據用戶名登陸<br>
     * 採用oauth2密碼模式獲取access_token和refresh_token
     *
     * @param username
     * @param password
     * @return
     */
    @SuppressWarnings("unchecked")
    @PostMapping("/sys/login")
    public Result<Map> login(@RequestParam String username,@RequestParam String password) {
        Map<String, String> parameters = new HashMap<>();
        parameters.put(OAuth2Utils.GRANT_TYPE, "password");
        parameters.put(OAuth2Utils.CLIENT_ID, "system");
        parameters.put("client_secret", "system");
        parameters.put(OAuth2Utils.SCOPE, "app");
//    parameters.put("username", username);
        // 爲了支持多類型登陸,這裏在username後拼裝上登陸類型
        parameters.put("username", username + "|" + CredentialType.USERNAME.name());
        parameters.put("password", password);

        Map<String, Object> tokenInfo = oauth2Client.postAccessToken(parameters);
        AppUser user = userClient.findUserByName(username);
        tokenInfo.put("user",user);
        saveLoginLog(username, "用戶名密碼登錄");

        return Result.success(tokenInfo);
    }

在feign的框架源碼中,有3個類是比較重要的,FeignClientFactoryBean,FeignContext,SynchronousMethodHandler.springboot

咱們先來看一下@EnableFeignClients的做用。網絡

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)  //用於處理@FeignClient註解
public @interface EnableFeignClients {
   //如下這三個都是用於指定須要掃描的包
   String[] value() default {};
   String[] basePackages() default {};
   Class<?>[] basePackageClasses() default {};
   //用於自定義feign client的自定義配置,能夠配置Decoder(解碼器),Encoder(編碼器)和Contract等組件,    //FeignClientsConfiguration是默認的配置類
   Class<?>[] defaultConfiguration() default {};
   //指定被@FeignClient修飾的類,若是不爲空,那麼路徑自動檢測機制會被關閉
   Class<?>[] clients() default {};
}

@Import註解有四個做用app

  1. 聲明一個bean
  2. 導入@Configuration註解的配置類
  3. 導入ImportSelector的實現類
  4. 導入ImportBeanDefinitionRegistrar的實現類

FeignClientsRegistrar是用來處理@FeignClient修飾的FeignClient接口類,將這些接口類的BeanDefinition註冊到Spring容器中,這樣就可使用@Autowired等方式來自動裝載這些@FeignClient接口類的Bean實例。框架

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
      ResourceLoaderAware, EnvironmentAware

FeignClientsRegistrar實現了ImportBeanDefinitionRegistrar接口,該接口是Spring實現bean動態注入的。咱們來看一下該接口的方法ide

public void registerBeanDefinitions(
      AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

在FeignClientsRegistrar中的實現微服務

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
      BeanDefinitionRegistry registry) {
   //從EnableFeignClients的屬性值來構建Feign的自定義Configuration進行註冊
   registerDefaultConfiguration(metadata, registry);
   //掃描package,註冊被@FeignClient修飾的接口類的Bean信息
   registerFeignClients(metadata, registry);
}
private void registerDefaultConfiguration(AnnotationMetadata metadata,
      BeanDefinitionRegistry registry) {
   //將@EnableFeignClients的全部屬性值導入map中
   Map<String, Object> defaultAttrs = metadata
         .getAnnotationAttributes(EnableFeignClients.class.getName(), true);
   //若是@EnableFeignClients配置了defaultConfiguration,則往下運行。若是沒有,rantion
   //會使用默認的FeignConfiguration,通常咱們這裏不會設置這些配置,都是默認,可是若是設置了,
   //就會比如咱們本身寫了@Configuration的類同樣的效果,這裏是自動配置了
   if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
      String name;
      //若是原始類中有內部類,獲取內部類名
      if (metadata.hasEnclosingClass()) {
         name = "default." + metadata.getEnclosingClassName();
      }
      //不然獲取原始類名
      else {
         name = "default." + metadata.getClassName();
      }
      //註冊@EnableFeignClients的Configuration配置
      registerClientConfiguration(registry, name,
            defaultAttrs.get("defaultConfiguration"));
   }
}
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
      Object configuration) {
   //獲取一個FeignClientSpecification的建造器
   BeanDefinitionBuilder builder = BeanDefinitionBuilder
         .genericBeanDefinition(FeignClientSpecification.class);
   //傳入構造參數
   builder.addConstructorArgValue(name);
   builder.addConstructorArgValue(configuration);
   //將FeignClientSpecification當成內部類對象進行註冊
   registry.registerBeanDefinition(
         name + "." + FeignClientSpecification.class.getSimpleName(),
         builder.getBeanDefinition());
}

以上這裏能夠方便咱們學習怎麼寫一個標籤達到自動配置效果。如下是掃描包,並把打了@FeignClient標籤的接口給加載到Spring容器中。post

public void registerFeignClients(AnnotationMetadata metadata,
      BeanDefinitionRegistry registry) {
   //獲取掃描器
   ClassPathScanningCandidateComponentProvider scanner = getScanner();
   scanner.setResourceLoader(this.resourceLoader);

   Set<String> basePackages;
   //將@EnableFeignClients的全部自定義配置屬性放入內存map中
   Map<String, Object> attrs = metadata
         .getAnnotationAttributes(EnableFeignClients.class.getName());
   //初始化一個@FeignClient的標籤類型過濾器
   AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
         FeignClient.class);
   //若是設置了@EnableFeignClients的自定義配置,獲取clients配置項中的Class數組
   final Class<?>[] clients = attrs == null ? null
         : (Class<?>[]) attrs.get("clients");
   //若是沒有自定義配置
   if (clients == null || clients.length == 0) {
      //掃描器添加標籤過濾類型
      scanner.addIncludeFilter(annotationTypeFilter);
      //獲取默認配置掃描包集合
      basePackages = getBasePackages(metadata);
   }
   else { //若是有自定義配置
      final Set<String> clientClasses = new HashSet<>();
      basePackages = new HashSet<>();
      //遍歷配置的每個client Class
      for (Class<?> clazz : clients) {
         //添加每個client Class的包
         basePackages.add(ClassUtils.getPackageName(clazz));
         //添加每個client Class的類名(包含內部類名)
         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) {
      //用掃描器掃描包,獲取bean集合
      Set<BeanDefinition> candidateComponents = scanner
            .findCandidateComponents(basePackage);
      //遍歷掃描到的bean集合
      for (BeanDefinition candidateComponent : candidateComponents) {
         //若是該bean爲一個標籤訂義的bean
         if (candidateComponent instanceof AnnotatedBeanDefinition) {
            // verify annotated class is an interface
            AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
            //獲取該bean的元數據
            AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
            //斷言該bean爲一個接口(Interface)
            Assert.isTrue(annotationMetadata.isInterface(),
                  "@FeignClient can only be specified on an interface");
            //獲取@FeignClient的全部屬性放入map中
            Map<String, Object> attributes = annotationMetadata
                  .getAnnotationAttributes(
                        FeignClient.class.getCanonicalName());
            //獲取@FeignClient配置的name(name或者value或者serviceId必須配置一個,並取其一)
            String name = getClientName(attributes);
            //註冊單個@FeignClient的Configuration配置
            registerClientConfiguration(registry, name,
                  attributes.get("configuration"));
            //註冊@FeignClient定義的bean
            registerFeignClient(registry, annotationMetadata, attributes);
         }
      }
   }
}

這裏咱們須要看一下@FeignClient標籤有哪些屬性

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {

   /**
    * name:指定FeignClient的名稱,若是項目使用了Ribbon,name屬性會做爲微服務的名稱,用於服務發現
    */
   @AliasFor("name")
   String value() default "";

   /**
    * name:指定FeignClient的名稱,若是項目使用了Ribbon,name屬性會做爲微服務的名稱,用於服務發現
    */
   @Deprecated
   String serviceId() default "";

   /**
    * name:指定FeignClient的名稱,若是項目使用了Ribbon,name屬性會做爲微服務的名稱,用於服務發現
    */
   @AliasFor("value")
   String name() default "";
   
   /**
    * 限定符
    */
   String qualifier() default "";

   /**
    * url通常用於調試,能夠手動指定@FeignClient調用的地址
    */
   String url() default "";

   /**
    * 當發生http 404錯誤時,若是該字段位true,會調用decoder進行解碼,不然拋出FeignException
    */
   boolean decode404() default false;

   /**
    * Feign配置類,能夠自定義Feign的Encoder、Decoder、LogLevel、Contract
    */
   Class<?>[] configuration() default {};

   /**
    * 定義容錯的處理類,當調用遠程接口失敗或超時時,會調用對應接口的容錯邏輯,fallback指定的類必須實現@FeignClient標記的接口
    */
   Class<?> fallback() default void.class;

   /**
    * 工廠類,用於生成fallback類示例,經過這個屬性咱們能夠實現每一個接口通用的容錯邏輯,減小重複的代碼
    */
   Class<?> fallbackFactory() default void.class;

   /**
    * 定義當前FeignClient的統一前綴
    */
   String path() default "";

   /**
    * 標記feign代理爲主bean
    */
   boolean primary() default true;

}
private String getClientName(Map<String, Object> client) {
   if (client == null) {
      return null;
   }
   //獲取@FeignClient配置的value
   String value = (String) client.get("value");
   if (!StringUtils.hasText(value)) {
      //若是value爲空,獲取@FeignClient配置的name
      value = (String) client.get("name");
   }
   if (!StringUtils.hasText(value)) {
      //若是value爲空,獲取@FeignClient配置的serviceId
      value = (String) client.get("serviceId");
   }
   //若是value不爲空,返回value
   if (StringUtils.hasText(value)) {
      return value;
   }

   throw new IllegalStateException("Either 'name' or 'value' must be provided in @"
         + FeignClient.class.getSimpleName());
}
private void registerFeignClient(BeanDefinitionRegistry registry,
      AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
   //獲取被@FeignClient標籤註解的類名稱,這裏是接口名
   String className = annotationMetadata.getClassName();
   //設置bean建造器的bean工廠
   BeanDefinitionBuilder definition = BeanDefinitionBuilder
         .genericBeanDefinition(FeignClientFactoryBean.class);
   //斷言@FeignClient配置的fallback,fallbackFactory必須爲接口
   validate(attributes);
   //建造器添加@FeignClient各配置屬性
   definition.addPropertyValue("url", getUrl(attributes));
   definition.addPropertyValue("path", getPath(attributes));
   String name = getName(attributes);
   definition.addPropertyValue("name", name);
   definition.addPropertyValue("type", className);
   definition.addPropertyValue("decode404", attributes.get("decode404"));
   definition.addPropertyValue("fallback", attributes.get("fallback"));
   definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
   definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

   String alias = name + "FeignClient";
   //使用該建造器建造bean
   AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
   //獲取主bean標識
   boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null
   //設置該bean是否爲主bean
   beanDefinition.setPrimary(primary);
   //經過@FeignClient設置的限定符屬性獲取別名
   String qualifier = getQualifier(attributes);
   if (StringUtils.hasText(qualifier)) {
      alias = qualifier;
   }
   //初始化一個bean的類名、別名解析器
   BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
         new String[] { alias });
   //經過bean工廠和別名解析器,將該bean註冊到spring容器中
   BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
private void validate(Map<String, Object> attributes) {
   AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes);
   // This blows up if an aliased property is overspecified
   // FIXME annotation.getAliasedString("name", FeignClient.class, null);
   Assert.isTrue(
      !annotation.getClass("fallback").isInterface(),
      "Fallback class must implement the interface annotated by @FeignClient"
   );
   Assert.isTrue(
      !annotation.getClass("fallbackFactory").isInterface(),
      "Fallback factory must produce instances of fallback classes that implement the interface annotated by @FeignClient"
   );
}

咱們在這裏看到了FeignClientFactoryBean的工廠類,它的做用就是實例化bean的,因爲咱們的bean是接口,要實例化成對象,咱們須要來看一下它的getObject()方法。

@Override
public Object getObject() throws Exception {
   //在Spring容器中拿取FeignContext對象bean
   FeignContext context = applicationContext.getBean(FeignContext.class);
   //從feignContext上下文中獲取Feign的建造器
   Feign.Builder builder = feign(context);
   //若是在@FeignClient中未設置url屬性
   if (!StringUtils.hasText(this.url)) {
      String url;
      //若是@FeignClient的name屬性以"http"開頭
      if (!this.name.startsWith("http")) {
         //設置url的值爲http://name
         url = "http://" + this.name;
      }
      else {
         //不然設置url爲name
         url = this.name;
      }
      
      url += cleanPath();
      return loadBalance(builder, context, new HardCodedTarget<>(this.type,
            this.name, url));
   }
   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) {
         // not lod balancing because we have a url,
         // but ribbon is on the classpath, so unwrap
         client = ((LoadBalancerFeignClient)client).getDelegate();
      }
      builder.client(client);
   }
   Targeter targeter = get(context, Targeter.class);
   return 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的建造器bean實例builder
   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));
   // @formatter:on

   configureFeign(context, builder);

   return builder;
}
protected void configureFeign(FeignContext context, Feign.Builder builder) {
   FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
   if (properties != null) {
      if (properties.isDefaultToProperties()) {
         configureUsingConfiguration(context, builder);
         configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
         configureUsingProperties(properties.getConfig().get(this.name), builder);
      } else {
         configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
         configureUsingProperties(properties.getConfig().get(this.name), builder);
         configureUsingConfiguration(context, builder);
      }
   } else {
      configureUsingConfiguration(context, builder);
   }
}
protected void configureUsingConfiguration(FeignContext context, Feign.Builder builder) {
   Logger.Level level = getOptional(context, Logger.Level.class);
   if (level != null) {
      builder.logLevel(level);
   }
   Retryer retryer = getOptional(context, Retryer.class);
   if (retryer != null) {
      builder.retryer(retryer);
   }
   ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
   if (errorDecoder != null) {
      builder.errorDecoder(errorDecoder);
   }
   Request.Options options = getOptional(context, Request.Options.class);
   if (options != null) {
      builder.options(options);
   }
   Map<String, RequestInterceptor> requestInterceptors = context.getInstances(
         this.name, RequestInterceptor.class);
   if (requestInterceptors != null) {
      builder.requestInterceptors(requestInterceptors.values());
   }

   if (decode404) {
      builder.decode404();
   }
}
protected <T> T getOptional(FeignContext context, Class<T> type) {
   return context.getInstance(this.name, type);
}
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
      HardCodedTarget<T> target) {
   //Client是一個進行Http請求的類,爲後續的第二個問題打下伏筆
   Client client = getOptional(context, Client.class);
   if (client != null) {
      //建造器拼裝client對象
      builder.client(client);
      //從自己名稱的上下文中獲取Targeter的bean實例,這裏Targeter是一個接口
      //它有兩個實現類DefaultTargeter,HystrixTargeter
      //這裏進行了分岔,看上下文中註冊的是使用默認的Targeter仍是熔斷器的Targeter
      Targeter targeter = get(context, Targeter.class);
      //根據上下文中不一樣的註冊調用不一樣對象的target方法,這裏咱們具體看DefaultTargeter的方法
      return targeter.target(this, builder, context, target);
   }

   throw new IllegalStateException(
         "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
}
interface Targeter {
   <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
             Target.HardCodedTarget<T> target);
}
class DefaultTargeter implements Targeter {

   @Override
   public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
                  Target.HardCodedTarget<T> target) {
      //直接調用Feign建造器的方法
      return feign.target(target);
   }
}

在Feign中

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

因爲Feign是一個抽象類,這個newInstance爲一個抽象方法

public abstract <T> T newInstance(Target<T> target);

在ReflectiveFeign中,ReflectiveFeign爲Feign的子類,能夠說前面全部的鋪墊就是爲了這個方法。

@SuppressWarnings("unchecked")
@Override
public <T> T newInstance(Target<T> target) { //Target是一個接口,咱們這裏傳入的是它的內部實現類HardCodedTarget
  //獲取目標的方法的方法名和方法處理器映射
  Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
  Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
  List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
  //遍歷目標type(被@FeignClinet註解的接口)的全部方法
  for (Method method : target.type().getMethods()) {
    if (method.getDeclaringClass() == Object.class) {
      //若是目標type爲Object,跳到下一個method,這裏是說方法不來自普通類的頂層父類Object,按道理目標type(Class)不會爲普通類,只是接口
      continue;
    } else if(Util.isDefault(method)) { //若是該方法爲接口默認方法,即被default修飾的方法
      //初始化一個默認方法處理器對象
      DefaultMethodHandler handler = new DefaultMethodHandler(method);
      //將該處理器對象添加到defaultMethodHandlers列表中
      defaultMethodHandlers.add(handler);
      //將該處理器對象添加到methodToHandler映射中
      methodToHandler.put(method, handler);
    } else {
      //若是不是默認方法,從nameToHandler中取出方法處理器並放入methodToHandler映射中
      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;
}
//MethodMetadata各屬性
private String configKey;
private transient Type returnType;
private Integer urlIndex;
private Integer bodyIndex;
private Integer headerMapIndex;
private Integer queryMapIndex;
private boolean queryMapEncoded;
private transient Type bodyType;
private RequestTemplate template = new RequestTemplate();
private List<String> formParams = new ArrayList<String>();
private Map<Integer, Collection<String>> indexToName =
    new LinkedHashMap<Integer, Collection<String>>();
private Map<Integer, Class<? extends Expander>> indexToExpanderClass =
    new LinkedHashMap<Integer, Class<? extends Expander>>();
private Map<Integer, Boolean> indexToEncoded = new LinkedHashMap<Integer, Boolean>();
private transient Map<Integer, Expander> indexToExpander;
private final SynchronousMethodHandler.Factory factory; //同步方法處理器工廠
public Map<String, MethodHandler> apply(Target key) {
  //獲取目標對象的type(Class類)屬性的方法元數據列表
  //這裏的type其實就是被@FeignClient註解的接口,而接口的方法就是相似諸如  
  //@PostMapping("/users-anon/finduser") 
  //LoginAppUser findUserByName(@RequestParam("username") String username);
  List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
  Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
  //遍歷全部的方法元數據
  for (MethodMetadata md : metadata) {
    BuildTemplateByResolvingArgs buildTemplate;
    //若是方法參數爲@RequestParam,不爲@RequestBody
    if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
      //構造一個BuildFormEncodedTemplateFromArgs對象,BuildFormEncodedTemplateFromArgs是BuildTemplateByResolvingArgs的子類
      buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder);
    } else if (md.bodyIndex() != null) {
      //若是方法參數爲@RequestBody,構造BuildEncodedTemplateFromArgs對象,BuildEncodedTemplateFromArgs也爲BuildTemplateByResolvingArgs的子類
      buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder);
    } else {
      //若是沒有參數,構造BuildTemplateByResolvingArgs對象
      buildTemplate = new BuildTemplateByResolvingArgs(md);
    }
    //建立一個方法處理器,並放入到方法配置映射中
    result.put(md.configKey(),
               factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
  }
  return result;
}
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);
}
public static String configKey(Class targetType, Method method) {
  StringBuilder builder = new StringBuilder();
  //拼裝類名+「#」+方法名+「(」
  builder.append(targetType.getSimpleName());
  builder.append('#').append(method.getName()).append('(');
  //遍歷方法的參數類型
  for (Type param : method.getGenericParameterTypes()) {
    //根據參數類型的全部可能進行處理,獲取處理結果的類型
    param = Types.resolve(targetType, targetType, param);
    //拼接該類型的類名稱
    builder.append(Types.getRawType(param).getSimpleName()).append(',');
  }
  //若是方法有參數
  if (method.getParameterTypes().length > 0) {
    //移除最末尾的字符
    builder.deleteCharAt(builder.length() - 1);
  }
  //移除後拼裝),而後返回
  return builder.append(')').toString();
}
static Type resolve(Type context, Class<?> contextRawType, Type toResolve) {
  // This implementation is made a little more complicated in an attempt to avoid object-creation.
  while (true) {
    //若是參數類型爲泛型
    if (toResolve instanceof TypeVariable) {
      //強制轉化爲泛型
      TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve;
      //獲取泛型的類型
      toResolve = resolveTypeVariable(context, contextRawType, typeVariable);
      if (toResolve == typeVariable) {
        //返回該泛型的類型
        return toResolve;
      }

    } else if (toResolve instanceof Class && ((Class<?>) toResolve).isArray()) {
      //若是參數類型爲數組,將參數類型轉化爲類
      Class<?> original = (Class<?>) toResolve;
      //獲取數組的原類型,數組的原類型若是不是多維數組就不可能仍是數組
      Type componentType = original.getComponentType();
      //遞歸調用,獲取新的類型
      Type newComponentType = resolve(context, contextRawType, componentType);
      //若是新類型爲數組原類型,返回原參數類型的類(數組類型),不然返回封裝了新類型的泛型數組類型對象,該對象的類實現
      //泛型數組類型接口
      return componentType == newComponentType ? original : new GenericArrayTypeImpl(
          newComponentType);

    } else if (toResolve instanceof GenericArrayType) { //若是參數類型爲泛型數組類型
      GenericArrayType original = (GenericArrayType) toResolve;
      //獲取該泛型
      Type componentType = original.getGenericComponentType();
      //遞歸調用,獲取新類型
      Type newComponentType = resolve(context, contextRawType, componentType);
      //若是新類型就爲該泛型,返回原參數類型(轉化爲泛型數組類型),不然返回封裝了新類型的泛型數組類型對象,該對象的類實現
     //泛型數組類型接口
      return componentType == newComponentType ? original : new GenericArrayTypeImpl(
          newComponentType);

    } else if (toResolve instanceof ParameterizedType) { //若是參數類型爲參數化類型
      ParameterizedType original = (ParameterizedType) toResolve;
      //獲取該參數化類型的外部類
      Type ownerType = original.getOwnerType();
      //遞歸調用獲取新外部類型
      Type newOwnerType = resolve(context, contextRawType, ownerType);
      //判斷新外部類型與原外部類型是否不一樣
      boolean changed = newOwnerType != ownerType;
      //獲取參數化類型的全部參數類型
      Type[] args = original.getActualTypeArguments();
      //遍歷全部參數類型
      for (int t = 0, length = args.length; t < length; t++) {
        //遞歸調用每個參數類型獲取對應的新的類型
        Type resolvedTypeArgument = resolve(context, contextRawType, args[t]);
        //若是對應的新類型不一樣於原參數類型
        if (resolvedTypeArgument != args[t]) {
          //若是新外部類型爲原外部類型
          if (!changed) {
            //克隆新內存地址
            args = args.clone();
            //設定新外部類型與原外部類型不一樣
            changed = true;
          }
          //將新類型放入原參數類型數組中
          args[t] = resolvedTypeArgument;
        }
      }
      //若是新外部類型與原外部類型不一樣,返回封裝了新外部類型和原內部類以及參數化多參數數組的參數化類型對象
      //不然返回原參數化類型
      return changed
             ? new ParameterizedTypeImpl(newOwnerType, original.getRawType(), args)
             : original;

    } else if (toResolve instanceof WildcardType) { //若是參數類型爲通配符表達式類型,通配符表達式類型例如<? extends String>、<? super String>
      WildcardType original = (WildcardType) toResolve;
      //獲取通配符前類型數組
      Type[] originalLowerBound = original.getLowerBounds();
      //獲取通配符後類型數組
      Type[] originalUpperBound = original.getUpperBounds();
      //若是通配符下界類型能夠獲取
      if (originalLowerBound.length == 1) {
        //遞歸調用,獲取新下界類型
        Type lowerBound = resolve(context, contextRawType, originalLowerBound[0]);
        //若是新下界類型與原下界不一樣
        if (lowerBound != originalLowerBound[0]) {
          //返回封裝了以Object.class爲上界類型,新下界類型爲下界類型的通配符類型對象
          return new WildcardTypeImpl(new Type[]{Object.class}, new Type[]{lowerBound});
        }
      } else if (originalUpperBound.length == 1) { //若是通配符上界類型能夠獲取
        //遞歸調用,獲取新上界類型
        Type upperBound = resolve(context, contextRawType, originalUpperBound[0]);
        //若是新上界類型與原上界類型不一樣
        if (upperBound != originalUpperBound[0]) {
          //返回封裝了以新上界類型爲上界類型,空爲下界類型的通配符類型對象
          return new WildcardTypeImpl(new Type[]{upperBound}, EMPTY_TYPE_ARRAY);
        }
      }
      //若是以上都沒有,返回原類型
      return original;

    } else { //其餘狀況返回原參數類型
      return toResolve;
    }
  }
}
private static Type resolveTypeVariable(
    Type context, Class<?> contextRawType, TypeVariable<?> unknown) {
  //獲取泛型所在的類(Class)
  Class<?> declaredByRaw = declaringClassOf(unknown);

  //若是獲取爲null,直接返回該泛型
  if (declaredByRaw == null) {
    return unknown;
  }
  //檢測泛型所在類與目標類的關係(同類或者祖類),並取得目標類的該祖類(同類則相等,祖類則祖類與泛型所在類相等)
  Type declaredBy = getGenericSupertype(context, contextRawType, declaredByRaw);
  //若是該泛型所在類爲參數化類型(例如List<String> list的List<String> 爲參數化類型ParameterizedType)
  if (declaredBy instanceof ParameterizedType) {
    //獲取泛型在泛型所在類的第幾個參數
    int index = indexOf(declaredByRaw.getTypeParameters(), unknown);
    //返回該泛型類型
    return ((ParameterizedType) declaredBy).getActualTypeArguments()[index];
  }

  return unknown;
}
private static Class<?> declaringClassOf(TypeVariable<?> typeVariable) {
  //獲取泛型所在的類
  GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
  //若是泛型所在的是類的話,返回該類(Class)
  return genericDeclaration instanceof Class ? (Class<?>) genericDeclaration : null;
}
static Type getGenericSupertype(Type context, Class<?> rawType, Class<?> toResolve) {
  //若是泛型所屬的類爲目標類,返回目標類
  if (toResolve == rawType) {
    return context;
  }
  //若是泛型所屬的類並不是目標類,說明是父類的
  //且泛型所屬的類爲接口
  if (toResolve.isInterface()) {
    //獲取目標類(實際上是接口)的全部父接口
    Class<?>[] interfaces = rawType.getInterfaces();
    //遍歷全部的父接口
    for (int i = 0, length = interfaces.length; i < length; i++) {
      //若是泛型所屬的類爲其中之一
      if (interfaces[i] == toResolve) {
        //返回目標類的帶泛型的父接口
        return rawType.getGenericInterfaces()[i];
      } else if (toResolve.isAssignableFrom(interfaces[i])) { //若是泛型所屬的類爲目標類父接口的父接口
        //遞歸調用,一直查找到泛型所屬的類匹配上目標類的某一個上層接口(祖先接口)爲止,返回目標類帶泛型的祖先接口
        return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve);
      }
    }
  }

  //若是目標類不爲接口(這個幾乎不可能)
  if (!rawType.isInterface()) {
    //當目標類不爲對象類時
    while (rawType != Object.class) {
      //獲取目標類的父類
      Class<?> rawSupertype = rawType.getSuperclass();
      //若是目標類的父類爲泛型所屬類
      if (rawSupertype == toResolve) {
        //返回目標類帶泛型的父類
        return rawType.getGenericSuperclass();
      } else if (toResolve.isAssignableFrom(rawSupertype)) { //若是泛型所屬類爲目標類父類的父類
        //遞歸調用,一直查找到泛型所屬的類匹配上目標類的某一個祖類爲止,返回目標類帶泛型的祖類
        return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve);
      }
      //不斷向祖類查找,直到找到對象類(Object類)爲止
      rawType = rawSupertype;
    }
  }

  //若是實在找不到,返回泛型所屬類(Class是Type接口的實現類)
  return toResolve;
}
private static int indexOf(Object[] array, Object toFind) {
  for (int i = 0; i < array.length; i++) {
    if (toFind.equals(array[i])) {
      return i;
    }
  }
  throw new NoSuchElementException();
}
static Class<?> getRawType(Type type) {
  if (type instanceof Class<?>) {
    //若是type爲普通類,返回type
    return (Class<?>) type;

  } else if (type instanceof ParameterizedType) { //若是type爲參數化類型
    ParameterizedType parameterizedType = (ParameterizedType) type;

    //獲取帶參數化類型自己的類型
    Type rawType = parameterizedType.getRawType();
    //若是該類型不爲類拋出異常
    if (!(rawType instanceof Class)) {
      throw new IllegalArgumentException();
    }
    //返回該類型的類
    return (Class<?>) rawType;

  } else if (type instanceof GenericArrayType) { //若是type爲泛型數組類型
    //獲取數組的原泛型
    Type componentType = ((GenericArrayType) type).getGenericComponentType();
    //返回數組的類class [Ljava.lang.Object;
    return Array.newInstance(getRawType(componentType), 0).getClass();

  } else if (type instanceof TypeVariable) { //若是type爲泛型
    //返回Object類
    return Object.class;

  } else if (type instanceof WildcardType) { //若是type爲通配符類型
    //返回通配符上界類型遞歸後的結果
    return getRawType(((WildcardType) type).getUpperBounds()[0]);

  } else { //都不是則拋出異常
    String className = type == null ? "null" : type.getClass().getName();
    throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
                                       + "GenericArrayType, but <" + type + "> is of type "
                                       + className);
  }
}
@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
  return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}
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);
  }

  @Override
  public boolean equals(Object obj) {
    if (obj instanceof FeignInvocationHandler) {
      FeignInvocationHandler other = (FeignInvocationHandler) obj;
      return target.equals(other.target);
    }
    return false;
  }

  @Override
  public int hashCode() {
    return target.hashCode();
  }

  @Override
  public String toString() {
    return target.toString();
  }
}

在Contract中

@Override
public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {
  //檢查傳入的Class是否有參數,有參數會報錯
  checkState(targetType.getTypeParameters().length == 0, "Parameterized types unsupported: %s",
             targetType.getSimpleName());
  //檢查傳入的Class(通常爲接口)是否有多個父接口,有多個父接口會報錯,最多支持一個父接口
  checkState(targetType.getInterfaces().length <= 1, "Only single inheritance supported: %s",
             targetType.getSimpleName());
  //若是傳入的Class有一個接口
  if (targetType.getInterfaces().length == 1) {
    //檢查該接口是否有祖父接口,有會拋出異常,不容許父接口還有父接口
    checkState(targetType.getInterfaces()[0].getInterfaces().length == 0,
               "Only single-level inheritance supported: %s",
               targetType.getSimpleName());
  }
  Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
  //遍歷傳入的Class的全部方法
  for (Method method : targetType.getMethods()) {
    //若是傳入的Class爲Object或者該方法爲靜態方法或者該方法爲接口默認方法
    if (method.getDeclaringClass() == Object.class ||
        (method.getModifiers() & Modifier.STATIC) != 0 ||
        Util.isDefault(method)) {
      //跳到下一個method
      continue;
    }
    //將傳入的Class和每個method解析爲方法元數據
    MethodMetadata metadata = parseAndValidateMetadata(targetType, method);
    checkState(!result.containsKey(metadata.configKey()), "Overrides unsupported: %s",
               metadata.configKey());
    //將元數據放入map中
    result.put(metadata.configKey(), metadata);
  }
  //返回符合條件的元數據列表
  return new ArrayList<MethodMetadata>(result.values());
}
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
  //初始化一個方法元數據對象
  MethodMetadata data = new MethodMetadata();
  //設置該對象的返回類型
  data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
  //設置該對象的configKey
  data.configKey(Feign.configKey(targetType, method));
  //若是目標類(接口)有一個父接口
  if(targetType.getInterfaces().length == 1) {
    processAnnotationOnClass(data, targetType.getInterfaces()[0]);
  }
  processAnnotationOnClass(data, targetType);


  for (Annotation methodAnnotation : method.getAnnotations()) {
    processAnnotationOnMethod(data, methodAnnotation, method);
  }
  checkState(data.template().method() != null,
             "Method %s not annotated with HTTP method type (ex. GET, POST)",
             method.getName());
  Class<?>[] parameterTypes = method.getParameterTypes();
  Type[] genericParameterTypes = method.getGenericParameterTypes();

  Annotation[][] parameterAnnotations = method.getParameterAnnotations();
  int count = parameterAnnotations.length;
  for (int i = 0; i < count; i++) {
    boolean isHttpAnnotation = false;
    if (parameterAnnotations[i] != null) {
      isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);
    }
    if (parameterTypes[i] == URI.class) {
      data.urlIndex(i);
    } else if (!isHttpAnnotation) {
      checkState(data.formParams().isEmpty(),
                 "Body parameters cannot be used with form parameters.");
      checkState(data.bodyIndex() == null, "Method has too many Body parameters: %s", method);
      data.bodyIndex(i);
      data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i]));
    }
  }

  if (data.headerMapIndex() != null) {
    checkMapString("HeaderMap", parameterTypes[data.headerMapIndex()], genericParameterTypes[data.headerMapIndex()]);
  }

  if (data.queryMapIndex() != null) {
    checkMapString("QueryMap", parameterTypes[data.queryMapIndex()], genericParameterTypes[data.queryMapIndex()]);
  }

  return data;
}

如下這個processAnnotationOnClass爲SpringMvcContract中的,而不是Default中的。

@Override
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
   //若是父接口沒有父接口
   if (clz.getInterfaces().length == 0) {
      RequestMapping classAnnotation = findMergedAnnotation(clz,
            RequestMapping.class);
      if (classAnnotation != null) {
         // Prepend path from class annotation if specified
         if (classAnnotation.value().length > 0) {
            String pathValue = emptyToNull(classAnnotation.value()[0]);
            pathValue = resolve(pathValue);
            if (!pathValue.startsWith("/")) {
               pathValue = "/" + pathValue;
            }
            data.template().insert(0, pathValue);
         }
      }
   }
}
/*
 * AnnotatedElement是全部可註釋元素(能夠是Class,Method,Field,Constructor,Package等)的接口
 */
@Nullable
public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement element, Class<A> annotationType) {
   //若是該元素不爲類,但這裏傳進來的是目標接口的父接口
   if (!(element instanceof Class)) {
      //獲取該元素的註釋
      A annotation = element.getAnnotation(annotationType);
      if (annotation != null) {
         return AnnotationUtils.synthesizeAnnotation(annotation, element);
      }
   }

   // Exhaustive retrieval of merged annotation attributes...
   AnnotationAttributes attributes = findMergedAnnotationAttributes(element, annotationType, false, false);
   return (attributes != null ? AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element) : null);
}

在NamedContextFactory中,NamedContextFactory是FeignContext的父類,而且是一個抽象類

這裏咱們能夠看到NamedContextFactory實現了ApplicationContextAware接口,便可以獲取Spring上下文。

public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
      implements DisposableBean, ApplicationContextAware
//NamedContextFactory的內部接口
public interface Specification {
   String getName();
   //獲取配置類數組
   Class<?>[] getConfiguration();
}
//名稱與標籤配置Spring上下文容器的映射,AnnotationConfigApplicationContext是專門用來作標籤配置加載Spring應用上下文。
//從而避免使用xml配置
private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();
//名稱與內部接口實現類的映射
private Map<String, C> configurations = new ConcurrentHashMap<>();
//默認配置類
private Class<?> defaultConfigType;
protected <T> T get(FeignContext context, Class<T> type) {
   //從自己名稱的上下文中獲取type類的bean實例
   T instance = context.getInstance(this.name, type);
   if (instance == null) {
      throw new IllegalStateException("No bean found of type " + type + " for "
            + this.name);
   }
   return instance;
}
public <T> T getInstance(String name, Class<T> type) {
   //獲取該名稱的上下文,若是該名稱的上下文不存在,則建立一個新的
   AnnotationConfigApplicationContext context = getContext(name);
   //若是type類在該名稱上下文中有註冊的bean,此處type不能爲一個接口
   if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
         type).length > 0) {
      //返回該名稱上下文中的bean
      return context.getBean(type);
   }
   return null;
}
protected AnnotationConfigApplicationContext getContext(String name) {
   //若是contexts中不包含該名稱
   if (!this.contexts.containsKey(name)) {
      synchronized (this.contexts) { //對contexts進行同步鎖定
         if (!this.contexts.containsKey(name)) {
            //建立一個新的context,並放入contexts中
            this.contexts.put(name, createContext(name));
         }
      }
   }
   //返回該名稱的標籤配置上下文
   return this.contexts.get(name);
}
protected AnnotationConfigApplicationContext createContext(String name) {
   //初始化一個標籤配置上下文對象
   AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
   //若是內部接口實現類映射中包含該名稱
   if (this.configurations.containsKey(name)) {
      //遍歷該名稱的內部接口實現類的全部配置類(數組)
      for (Class<?> configuration : this.configurations.get(name)
            .getConfiguration()) {
         //將每個配置類註冊到標籤配置上下文中
         context.register(configuration);
      }
   }
   //遍歷內部接口實現類的每一對映射
   for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
      //若是名稱以"default."開頭
      if (entry.getKey().startsWith("default.")) {
         //遍歷該名稱的內部接口實現類的全部配置類(數組)
         for (Class<?> configuration : entry.getValue().getConfiguration()) {
            //將每個配置類註冊到標籤配置上下文中
            context.register(configuration);
         }
      }
   }
   //註冊自動裝配類和默認配置類
   context.register(PropertyPlaceholderAutoConfiguration.class,
         this.defaultConfigType);
   context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(
         this.propertySourceName,
         Collections.<String, Object> singletonMap(this.propertyName, name)));
   if (this.parent != null) {
      // Uses Environment from parent as well as beans
      context.setParent(this.parent);
   }
   context.setDisplayName(generateDisplayName(name));
   //以上註冊的bean,context必須刷新纔可使用
   context.refresh();
   return context;
}

在BeanFactoryUtils中,首先咱們要先看一張AnnotationConfigApplicationContext繼承圖,圖中代表AnnotationConfigApplicationContext是實現了ListableBeanFactory接口的。

由如下代碼能夠看出,此處是找出一個Class在Spring上下文中,不管是在哪個層級的上下文(Spring有不少層級的上下文,就上面這張圖裏標示出來的)註冊的,均可以找出來,並把這些類名稱放到一個數組中。若是Class是一個接口,則能夠找出它全部的被註冊到Spring容器的實現類(若是未被Spring上下文註冊是找不到的)

public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class<?> type) {
   //這裏咱們把ListableBeanFactory lbf就當作標籤配置上下文AnnotationConfigApplicationContext對象
   //斷言上下文對象不能爲null
   Assert.notNull(lbf, "ListableBeanFactory must not be null");
   //獲取type的全部類名稱(這裏包括父類和全部子類)
   String[] result = lbf.getBeanNamesForType(type);
   //此處爲真,由於AnnotationConfigApplicationContext也實現了HierarchicalBeanFactory接口
   if (lbf instanceof HierarchicalBeanFactory) {
      //強制轉化成HierarchicalBeanFactory(有分層的bean工廠)接口的實例
      HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
      //若是hbf的父bean工廠爲ListableBeanFactory(可列表的bean工廠)
      if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
         //遞歸hbf的父bean工廠,獲取父bean工廠中,type的全部類名稱(父子類)
         String[] parentResult = beanNamesForTypeIncludingAncestors(
               (ListableBeanFactory) hbf.getParentBeanFactory(), type);
         //組合當前結果和父bean工廠的結果
         result = mergeNamesWithParent(result, parentResult, hbf);
      }
   }
   //返回該結果
   return result;
}
private static String[] mergeNamesWithParent(String[] result, String[] parentResult, HierarchicalBeanFactory hbf) {
   //若是type在父bean工廠沒有類名稱,直接返回result
   if (parentResult.length == 0) {
      return result;
   }
   //組合當前結果和父bean工廠結果數組
   List<String> merged = new ArrayList<>(result.length + parentResult.length);
   merged.addAll(Arrays.asList(result));
   for (String beanName : parentResult) {
      if (!merged.contains(beanName) && !hbf.containsLocalBean(beanName)) {
         merged.add(beanName);
      }
   }
   //將組合結果由List轉回數組返回
   return StringUtils.toStringArray(merged);
}
相關文章
相關標籤/搜索