上文我们已经分析到FeignClientFactoryBean#getTarget()方法,这里完成了FeignClient动态代理的创建。但并未分析具体的创建过程,本文将深入Feign Core将FeignClient到底是如何被创建出来的给摸清楚。

1
2
3
4
5
6
7
8
class HystrixTargeter implements Targeter {

@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
return feign.target(target);
}
  • 我们此时并未整合Hystrix,所以此处的feign还是Feign.Builder,此处直接走他的target方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract class Feign {
public static class Builder {
private InvocationHandlerFactory invocationHandlerFactory =
new InvocationHandlerFactory.Default();

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

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);
}
  • SynchronousMethodHandler
    同步方法处理器

  • invocationHandlerFactory
    invocationHandler这东西怎么这么眼熟呢,这不是JDK动态代理那个套路里的接口吗?我们一探究竟

    1
    2
    3
    4
    5
    6
    7
    static final class Default implements InvocationHandlerFactory {

    @Override
    public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
    return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
    }
    }
    • 这包裹的层次够深的,我们看看这个FeignInvoccationHandler是啥

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      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);
      }

      到此,终于真相大白,验证了我们根据命名得到的猜测,这确实是使用了JDK的动态代理技术,这个invoke方法我们后续再分析,其实也不难推测,无非是拦截对ServiceAClient的方法的调用,委托到这个FeignInvocationHandler#invoke(),然后执行feign的逻辑,最后就是调用底层的一个HTTP客户端,根据我们的RequestMapping等注解里的参数拼接一个HTTP Request,发送出去罢了

  • 接上build().newInstance(target)build()出了一个ReflectiveFeign对象,然后调用它的newInstance()方法,在这里,最终完成了基于JDK动态代理的FeignClient的创建

柳暗花明,看ReflectiveFeign#newInstance()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class ReflectiveFeign

public <T> T newInstance(Target<T> target) {
// 这个apply会调用SpringMvcContract将注解都解析出来,放到Feign的RequestTemplate中去
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 {
// 就是简单的组装了一个ServiceAClient中方法对象 -> SynchronousMethodHandler的映射
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}

// 接下来就是最后的基于JDK动态代理创建Proxy对象实例了
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;
}

下面的部分是各个步骤的详细剖析,没兴趣的同学可以不看了,在这里已经完成了所有关于FeignClient创建的核心知识了。

  • nameToHandler
    看名字就可以猜测是什么东西的名称和代理方法处理器的映射

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class ReflectiveFeign

    public Map<String, MethodHandler> apply(Target key) {
    // 这里执行了SpringMvcContract组件的解析SpringMVC注解的逻辑,最后解析后组成了一个List
    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;
    }
  • contract.parseAndValidateMetadata
    这里就轮到SpringMvcContract组件闪亮登场了,他负责对ReqeustMappingPathVaraiable等注解的解析

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    abstract class BaseContract implements Contract {

    @Override
    public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {
    Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
    // 使用反射,遍历ServiceAClient的每个方法
    for (Method method : targetType.getMethods()) {
    if (method.getDeclaringClass() == Object.class ||
    (method.getModifiers() & Modifier.STATIC) != 0 ||
    Util.isDefault(method)) {
    continue;
    }
    // 调用SpringMvcContract来具体处理注解
    MethodMetadata metadata = parseAndValidateMetadata(targetType, method);


    result.put(metadata.configKey(), metadata);
    }
    return new ArrayList<>(result.values());
    }
  • 通过反射遍历ServiceAClient中的每个方法,然后委托给SpringMvcContract#parseValidateMetadata处理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    class SpringMvcContract extends Contract.BaseContract

    @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) {
    // produces - use from class annotation only if method has not specified this
    if (!md.template().headers().containsKey(ACCEPT)) {
    parseProduces(md, method, classAnnotation);
    }

    // consumes -- use from class annotation only if method has not specified this
    if (!md.template().headers().containsKey(CONTENT_TYPE)) {
    parseConsumes(md, method, classAnnotation);
    }

    // headers -- class annotation is inherited to methods, always write these if
    // present
    parseHeaders(md, method, classAnnotation);
    }
    return md;
    }

Feign的封装当真是山路十八弯,父类子类各种相互调用,这点儿一点也不优雅

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
MethodMetadata data = new MethodMetadata();
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
data.configKey(Feign.configKey(targetType, method));

if (targetType.getInterfaces().length == 1) {
// 解析ServiceAClient类上的`RequestMapping`注解
processAnnotationOnClass(data, targetType.getInterfaces()[0]);
}
processAnnotationOnClass(data, targetType);

// 解析ServiceAClient方法上的`RequestMapping`注解
for (Annotation methodAnnotation : method.getAnnotations()) {
processAnnotationOnMethod(data, methodAnnotation, method);
}

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 && parameterTypes[i] != Request.Options.class) {

data.bodyIndex(i);
data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i]));
}
}

return data;
}
  • 解析ServiceAClient类上的RequestMapping注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;
}
// 这里template()其实是一个RequestTemplate
data.template().uri(pathValue);
}
}
}
}
  • 这里其实就是将ServiceAClient类上面RequestMapping注解中解析出url,然后将他发到Feign的RequestTemplate组件中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
protected void processAnnotationOnMethod(MethodMetadata data,
Annotation methodAnnotation, Method method) {

RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class);
// HTTP Method
RequestMethod[] methods = methodMapping.method();
// 如果你没有在`RequestMapping`里指定方法类型,那么默认就是GET方法
if (methods.length == 0) {
methods = new RequestMethod[] { RequestMethod.GET };
}

// 解析你在`RequestMapping`里指定的method类型,放到RequestTemplate中的method中去
data.template().method(Request.HttpMethod.valueOf(methods[0].name()));

// 解析你在RequestMapping中的path,拼接成url,放到RequestTemplate中的URL中去
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);
}
}

// 解析RequestMapping注解里的produces属性,将这些属性放到RequestTemplate中的header中的ACCEPT值里
parseProduces(data, method, methodMapping);

// 解析RequestMappinp注解的consumes属性,将这些属性放到RequestTemplate中的header中的CONTENT_TYPE值的
parseConsumes(data, method, methodMapping);

// 解析RequestMapping注解的headers属性,将这些属性放到RequestTemplate中的header键值对里去
parseHeaders(data, method, methodMapping);

data.indexToExpander(new LinkedHashMap<Integer, Param.Expander>());
}
  • 解析ServiceAClient中方法上的RequestMapping注解里各项属性
    • 如果你没有指定方法类型,那么默认就是GET方法
    • 解析method类型,放到RequestTemplate中的method中去
    • 解析path,拼接成url,放到RequestTemplate中的URL中去
    • 解析produces属性,将这些属性放到RequestTemplate中的header中的ACCEPT值里
    • 解析consumes属性,将这些属性放到RequestTemplate中的header中的CONTENT_TYPE值的
    • 解析headers属性,将这些属性放到RequestTemplate中的header键值对里去
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
protected boolean processAnnotationsOnParameter(MethodMetadata data,
Annotation[] annotations, int paramIndex) {
boolean isHttpAnnotation = false;

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;
// synthesize, handling @AliasFor, while falling back to parameter name on
// missing String #value():
processParameterAnnotation = synthesizeWithMethodParameterNameAsFallbackValue(
parameterAnnotation, method, paramIndex);
isHttpAnnotation |= processor.processArgument(context,
processParameterAnnotation, method);
}
}

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;
}
  • 解析ServiceAClient中方法上的入参

    • 默认的参数处理器,这几个处理器都是spring-cloud-openfeign-core工程的
      • 解析@PathVariablePathVariableParameterProcessor
      • 解析@RequestParamRequestParamParameterProcessor
      • 解析@ReqeustHeaderRequestHeaderParameterProcessor
      • 解析@QueryMap:QueryMapParameterProcessor
  • result.put(md.configKey(), factory.create(key, md, buildTemplate, options, decoder, errorDecoder));

    • create方法其实创建了一个SynchronousMethodHandler,将所有和serviceAClient中一个方法相关的东西都放了进去

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      final class SynchronousMethodHandler
      class Factory
      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);
      }

总结

feign对FeignClient的创建过程,个人觉得封装的并不是很优雅,山路十八弯,各种父子类调用,很容易让源码阅读者绕晕。
按照惯例,笔者放出总结大图一张。
Feign-FeignClient动态代理创建过程

Comments