Feign封裝請求基本原理(方法調用)


接上文“Feign封裝請求基本原理(啟動和注入)”,本文看一個Feign請求的過程。

一、遠程方法對應的MethodHandler創建

在注入Feign代理對象的bean時,會給@FeignClient注解接口下所有符合條件的方法生成對應的MethodHandler,該操作是在ReflectiveFeign#newInstance()方法中。

MethodHandler是遠程方法請求的實際處理器,這里是MethodHandler的實現類SynchronousMethodHandler的對象。

ReflectiveFeign#newInstance()方法

// ReflectiveFeign#newInstance(Target<T> target)
public <T> T newInstance(Target<T> target) {
	// 該方法會生成遠程方法對應的MethodHandler
	// ParseHandlersByName#apply(Target target)
    Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);

    // 省略了其他代碼
}

進入ReflectiveFeign$ParseHandlersByName#apply(Target target)方法

// ReflectiveFeign$ParseHandlersByName#apply(Target target)
// 本例中的target是 HardCodedTarget(type=FeignTest1Service, name=test1, url=http://hq.sinajs.cn)
public Map<String, MethodHandler> apply(Target target) {
  // contract是SpringMvcContract對象,SpringMvcContract繼承Contract$BaseContract類
  // 解析出每個方法對應的MethodMetadata
  List<MethodMetadata> metadata = contract.parseAndValidateMetadata(target.type());
  Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
  for (MethodMetadata md : metadata) {
  	// 實現了RequestTemplate$Factory接口,有一個create()用於創建請求模板RequestTemplate實例
    BuildTemplateByResolvingArgs buildTemplate;
    if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
      buildTemplate =
          new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
    } else if (md.bodyIndex() != null) {
      buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
    } else {
      buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder, target);
    }
    if (md.isIgnored()) {
      result.put(md.configKey(), args -> {
        throw new IllegalStateException(md.configKey() + " is not a method handled by feign");
      });
    } else {
      // factory.create()創建SynchronousMethodHandler實例
      result.put(md.configKey(),
          factory.create(target, md, buildTemplate, options, decoder, errorDecoder));
    }
  }
  return result;
}

關於請求路徑、參數和頭信息的初始化處理多是在SpringMvcContract類中。

看解析接口方法MethodMetadata,進入SpringMvcContract#parseAndValidateMetadata(Class<?> targetType),即Contract$BaseContract#parseAndValidateMetadata(Class<?> targetType)

// Contract$BaseContract#parseAndValidateMetadata(Class<?> targetType)
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
  // 不支持泛型 會拋異常
  checkState(targetType.getTypeParameters().length == 0, "Parameterized types unsupported: %s",
      targetType.getSimpleName());
  // 實現的接口不能超過1個 會拋異常
  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());
  }
  Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
  // 遍歷所有public方法
  for (Method method : targetType.getMethods()) {
  	// 合法的Feign方法不能是Object定義、靜態方法和接口默認方法
    if (method.getDeclaringClass() == Object.class ||
        (method.getModifiers() & Modifier.STATIC) != 0 ||
        Util.isDefault(method)) {
      continue;
    }
    // 解析出方法對應的 MethodMetadata。如解析請求path、produces、consumes和headers等,包括對類和方法上的注解
    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());
}

二、遠程方法的調用

1. 發起請求

2. 代理對象調用處理方法

Map<Method, MethodHandler> dispatch該對象緩存了遠程方法請求的實際的處理邏輯,通過Method對象定位。

FeignInvocationHandler#invoke(Object proxy, Method method, Object[] args)

equals()、hashCode()和toString()方法不會被處理。

 

dispatch.get(method).invoke(args),也就是進入SynchronousMethodHandler#invoke(Object[] argv)

BuildTemplateByResolvingArgs#create(Object[] argv)

SynchronousMethodHandler#targetRequest(RequestTemplate template),攔截器執行

SynchronousMethodHandler#executeAndDecode(RequestTemplate template, Options options),發起請求和返回處理

3. 執行結果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM