首页 > 技术文章 > Feign封装请求基本原理(方法调用)

doflamingo 2020-07-31 23:45 原文

接上文“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. 执行结果

 

推荐阅读