首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

openfeign的使用原理(二)

1、前言

在上一篇文章中,我们谈了openfeign借助一系列自动配置类帮我们自动创建feign client对象的一个过程,在文章最后,我们也提到,openfeign帮我们创建的feign client对象其实是一个代理对象,本篇我们将继续探讨下feign client代理对象的生成过程,由于相关代码不算太难理解,本篇文字并不多,主要是以展示源码内容为准。

2、原理讲解

我们从下列代码开始看起,其中build方法返回的是一个ReflectiveFeign对象。

//Feign.class

public?<T>?T?target(Target<T>?target)?{

return?build().newInstance(target);

}

ReflectiveFeign类的newInstance方法定义如下:

//?ReflectiveFeign.class

/**

*?creates?an?api?binding?to?the?{@code?target}.?As?this?invokes?reflection,?care?should?be?taken

*?to?cache?the?result.

*/

@SuppressWarnings("unchecked")

@Override

public?<T>?T?newInstance(Target<T>?target)?{

//重点,对接口方法标记了@RequestMapping(GetMapping、PostMapping等等)的方法进行提取转换

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?{

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;

}2.1、ParseHandlersByName.apply方法

ParseHandlersByName是ReflectiveFeign的一个静态内部类,它是根据接口方法名来创建对应的转换方法处理器。在创建ReflectiveFeign对象时,ReflectiveFeign的构造函数会接收一个ParseHandlersByName对象。我们来看下它的apply方法。

//ReflectiveFeign.ParseHandlersByName类

public?Map<String,?MethodHandler>?apply(Target?target)?{

//contract指的是SpringMvcContract对象,此代码获取接口里面所有的表示http请求的方法的元数据

List<MethodMetadata>?metadata?=?contract.parseAndValidateMetadata(target.type());

//为每个方法生成相应的MethodHandler

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,?target);

}?else?if?(md.bodyIndex()?!=?null?||?md.alwaysEncodeBody())?{

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?{

result.put(md.configKey(),

factory.create(target,?md,?buildTemplate,?options,?decoder,?errorDecoder));

}

}

return?result;

}

我们看下contract.parseAndValidateMetadata方法的实现:

//Contract类

@Override

public?List<MethodMetadata>?parseAndValidateMetadata(Class<?>?targetType)?{

checkState(targetType.getTypeParameters().length?==?0,?"Parameterized?types?unsupported:?%s",

targetType.getSimpleName());

//这里限制了targetType类对象指代的类或接口最多只能继承一个接口

checkState(targetType.getInterfaces().length?<=?1,?"Only?single?inheritance?supported:?%s",

targetType.getSimpleName());

final?Map<String,?MethodMetadata>?result?=?new?LinkedHashMap<String,?MethodMetadata>();

for?(final?Method?method?:?targetType.getMethods())?{

if?(method.getDeclaringClass()?==?Object.class?||

(method.getModifiers()?&?Modifier.STATIC)?!=?0?||

Util.isDefault(method))?{

continue;

}

/生成方法的元数据信息的关键点

final?MethodMetadata?metadata?=?parseAndValidateMetadata(targetType,?method);

if?(result.containsKey(metadata.configKey()))?{

MethodMetadata?existingMetadata?=?result.get(metadata.configKey());

Type?existingReturnType?=?existingMetadata.returnType();

Type?overridingReturnType?=?metadata.returnType();

Type?resolvedType?=?Types.resolveReturnType(existingReturnType,?overridingReturnType);

if?(resolvedType.equals(overridingReturnType))?{

result.put(metadata.configKey(),?metadata);

}

continue;

}

result.put(metadata.configKey(),?metadata);

}

return?new?ArrayList<>(result.values());

}2.1.1、SpringMvcContract类的parseAndValidateMetadata方法

parseAndValidateMetadata方法完成了对Feign接口内每个方法的元数据信息的提取工作。我们进入SpringMvcContract类看一下parseAndValidateMetadata(targetType, method)的实现:

//SpringMvcContract类

@Override

public?MethodMetadata?parseAndValidateMetadata(Class<?>?targetType,?Method?method)?{

//记录下需要处理的接口方法

processedMethods.put(Feign.configKey(targetType,?method),?method);

//调用父类BaseContract中的parseAndValidateMetadata,提取方法的元数据信息

return?super.parseAndValidateMetadata(targetType,?method);

}

BaseContract类,是Contract的子类,也是Contract类的一个内部抽象类,它的parseAndValidateMetadata方法对接口方法进行了剖析,提取出了和Http接口信息相关的信息,其实也就是springmvc中开发controller用到的那些注解。

//BaseContract类

protected?MethodMetadata?parseAndValidateMetadata(Class<?>?targetType,?Method?method)?{

final?MethodMetadata?data?=?new?MethodMetadata();

data.targetType(targetType);

data.method(method);

data.returnType(

Types.resolve(targetType,?targetType,?method.getGenericReturnType()));

//configkey,用来作为方法元数据对象的一个标识,是“类型#方法名(方法参数类型列表)”的形式

data.configKey(Feign.configKey(targetType,?method));

if?(AlwaysEncodeBodyContract.class.isAssignableFrom(this.getClass()))?{

data.alwaysEncodeBody(true);

}

//对targetType继承的接口进行处理,前提是只继承了一个接口

if?(targetType.getInterfaces().length?==?1)?{

processAnnotationOnClass(data,?targetType.getInterfaces()[0]);

}

//处理当前接口上面的注解,也就是targetType类对象所属的接口

processAnnotationOnClass(data,?targetType);

//对方法上的注解进行遍历处理

for?(final?Annotation?methodAnnotation?:?method.getAnnotations())?{

processAnnotationOnMethod(data,?methodAnnotation,?method);

}

if?(data.isIgnored())?{

return?data;

}

checkState(data.template().method()?!=?null,

"Method?%s?not?annotated?with?HTTP?method?type?(ex.?GET,?POST)%s",

data.configKey(),?data.warnings());

final?Class<?>[]?parameterTypes?=?method.getParameterTypes();

final?Type[]?genericParameterTypes?=?method.getGenericParameterTypes();

//处理方法参数上面的注解

final?Annotation[][]?parameterAnnotations?=?method.getParameterAnnotations();

final?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?(isHttpAnnotation)?{

data.ignoreParamater(i);

}

if?(parameterTypes[i]?==?URI.class)?{

data.urlIndex(i);

}?else?if?(!isHttpAnnotation?&&?parameterTypes[i]?!=?Request.Options.class)?{

if?(data.isAlreadyProcessed(i))?{

checkState(data.formParams().isEmpty()?||?data.bodyIndex()?==?null,

"Body?parameters?cannot?be?used?with?form?parameters.%s",?data.warnings());

}?else?if?(!data.alwaysEncodeBody())?{

checkState(data.formParams().isEmpty(),

"Body?parameters?cannot?be?used?with?form?parameters.%s",?data.warnings());

checkState(data.bodyIndex()?==?null,

"Method?has?too?many?Body?parameters:?%s%s",?method,?data.warnings());

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)?{

if?(Map.class.isAssignableFrom(parameterTypes[data.queryMapIndex()]))?{

checkMapKeys("QueryMap",?genericParameterTypes[data.queryMapIndex()]);

}

}

return?data;

}2.1.1.1、MethodMetaData中的configkey

每个接口方法都会有一个configKey属性,方便后续根据它来获取到MethodMetaData。

//configkey,用来作为方法元数据对象的一个标识,是“类型#方法名(方法参数类型列表)”的形式

data.configKey(Feign.configKey(targetType,?method));

我们看下Feign.configKey方法的内部实现:

//Feign类

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();

}

由上面代码可知,每个方法对应的configKey的值就是类似“类型#方法名(方法参数类型列表)”的形式,拿我们写的OrderClient接口中的findById方法来说,它的configKey的值就是"OrderClient#findById(Long)"。

2.1.1.2、processAnnotationOnClass方法

processAnnotationOnClass方法的主要作用只有一个,就是不允许@FeignClient所在的接口(包括父接口)上面存在@RequestMapping注解(GetMapping、PostMapping等也算),不然就会报错,导致系统无法启动。

//SpringMvcContract类

@Override

protected?void?processAnnotationOnClass(MethodMetadata?data,?Class<?>?clz)?{

RequestMapping?classAnnotation?=?findMergedAnnotation(clz,?RequestMapping.class);

if?(classAnnotation?!=?null)?{

LOG.error("Cannot?process?class:?"?+?clz.getName()

+?".?@RequestMapping?annotation?is?not?allowed?on?@FeignClient?interfaces.");

throw?new?IllegalArgumentException("@RequestMapping?annotation?not?allowed?on?@FeignClient?interfaces");

}

CollectionFormat?collectionFormat?=?findMergedAnnotation(clz,?CollectionFormat.class);

if?(collectionFormat?!=?null)?{

data.template().collectionFormat(collectionFormat.value());

}

}2.1.1.3、processAnnotationOnMethod方法

处理完接口上面的注解之后,接下来就要遍历处理接口内部方法上面所有的注解,完成这一功能的就是processAnnotationOnMethod方法,我们来看下它的内部实现:

//SpringMvcContract类

@Override

protected?void?processAnnotationOnMethod(MethodMetadata?data,?Annotation?methodAnnotation,?Method?method)?{

if?(CollectionFormat.class.isInstance(methodAnnotation))?{

CollectionFormat?collectionFormat?=?findMergedAnnotation(method,?CollectionFormat.class);

data.template().collectionFormat(collectionFormat.value());

}

if?(!RequestMapping.class.isInstance(methodAnnotation)

&&?!methodAnnotation.annotationType().isAnnotationPresent(RequestMapping.class))?{

return;

}

RequestMapping?methodMapping?=?findMergedAnnotation(method,?RequestMapping.class);

//?HTTP?Method

RequestMethod[]?methods?=?methodMapping.method();

if?(methods.length?==?0)?{

methods?=?new?RequestMethod[]?{?RequestMethod.GET?};

}

checkOne(method,?methods,?"method");

data.template().method(Request.HttpMethod.valueOf(methods[0].name()));

//?path

checkAtMostOne(method,?methodMapping.value(),?"value");

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);

if?(data.template().decodeSlash()?!=?decodeSlash)?{

data.template().decodeSlash(decodeSlash);

}

}

}

//?produces

parseProduces(data,?method,?methodMapping);

//?consumes

parseConsumes(data,?method,?methodMapping);

//?headers

parseHeaders(data,?method,?methodMapping);

data.indexToExpander(new?LinkedHashMap<>());

}

上面的方法很简单,主要就是处理接口方法上面的RequestMapping注解,包括提取path、header等信息。如果当前注解不是RequestMapping的实例,则会跳过当前注解,转而处理方法上面的下一个注解。

2.1.1.4、processAnnotationsOnParameter方法

处理完方法上面的所有注解之后,就是处理该方法的参数上面的注解,完成这一功能的是processAnnotationsOnParameter方法,我们来看下它的内部实现:

//SpringMvcContract类

@Override

protected?boolean?processAnnotationsOnParameter(MethodMetadata?data,?Annotation[]?annotations,?int?paramIndex)?{

boolean?isHttpAnnotation?=?false;

AnnotatedParameterProcessor.AnnotatedParameterContext?context?=?new?SimpleAnnotatedParameterContext(data,

paramIndex);

Method?method?=?processedMethods.get(data.configKey());

for?(Annotation?parameterAnnotation?:?annotations)?{

//根据当前的参数注解获取对应的注解参数处理器对象

AnnotatedParameterProcessor?processor?=?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?(!isMultipartFormData(data)?&&?isHttpAnnotation?&&?data.indexToExpander().get(paramIndex)?==?null)?{

TypeDescriptor?typeDescriptor?=?createTypeDescriptor(method,?paramIndex);

if?(conversionService.canConvert(typeDescriptor,?STRING_TYPE_DESCRIPTOR))?{

Param.Expander?expander?=?convertingExpanderFactory.getExpander(typeDescriptor);

if?(expander?!=?null)?{

data.indexToExpander().put(paramIndex,?expander);

}

}

}

return?isHttpAnnotation;

}

上面方法对方法参数注解处理的过程中用到了annotatedArgumentProcessors对象,它是map类型的,是在创建

SpringMvcContract对象(由FeignClientsConfiguration配置类创建)的时候生成的,map中存储的是openfeign提供的一些默认的注解参数处理器对象。核心代码如下:

//SpringMvcContract类

public?SpringMvcContract(List<AnnotatedParameterProcessor>?annotatedParameterProcessors,

ConversionService?conversionService,?boolean?decodeSlash)?{

Assert.notNull(annotatedParameterProcessors,?"Parameter?processors?can?not?be?null.");

Assert.notNull(conversionService,?"ConversionService?can?not?be?null.");

//获取默认的注解参数处理器

List<AnnotatedParameterProcessor>?processors?=?getDefaultAnnotatedArgumentsProcessors();

processors.addAll(annotatedParameterProcessors);

//将list格式的注解参数处理器转换为map形式

annotatedArgumentProcessors?=?toAnnotatedArgumentProcessorMap(processors);

this.conversionService?=?conversionService;

convertingExpanderFactory?=?new?ConvertingExpanderFactory(conversionService);

this.decodeSlash?=?decodeSlash;

}

private?List<AnnotatedParameterProcessor>?getDefaultAnnotatedArgumentsProcessors()?{

List<AnnotatedParameterProcessor>?annotatedArgumentResolvers?=?new?ArrayList<>();

annotatedArgumentResolvers.add(new?MatrixVariableParameterProcessor());

annotatedArgumentResolvers.add(new?PathVariableParameterProcessor());

annotatedArgumentResolvers.add(new?RequestParamParameterProcessor());

annotatedArgumentResolvers.add(new?RequestHeaderParameterProcessor());

annotatedArgumentResolvers.add(new?QueryMapParameterProcessor());

annotatedArgumentResolvers.add(new?RequestPartParameterProcessor());

annotatedArgumentResolvers.add(new?CookieValueParameterProcessor());

return?annotatedArgumentResolvers;

}

private?Map<Class<??extends?Annotation>,?AnnotatedParameterProcessor>?toAnnotatedArgumentProcessorMap(

List<AnnotatedParameterProcessor>?processors)?{

Map<Class<??extends?Annotation>,?AnnotatedParameterProcessor>?result?=?new?HashMap<>();

for?(AnnotatedParameterProcessor?processor?:?processors)?{

result.put(processor.getAnnotationType(),?processor);

}

return?result;

}

每个处理器都声明了自己能处理的注解类型,比如PathVariableParameterProcessor只能处理@PathVariable注解:

public?class?PathVariableParameterProcessor?implements?AnnotatedParameterProcessor?{

private?static?final?Class<PathVariable>?ANNOTATION?=?PathVariable.class;

public?PathVariableParameterProcessor()?{

}

public?Class<??extends?Annotation>?getAnnotationType()?{

return?ANNOTATION;

}

。。。

}2.2.1、为每个方法生成对应的MethodHandler

我们继续看apply方法,该方法后面有这么一段代码:

result.put(md.configKey(),

factory.create(target,?md,?buildTemplate,?options,?decoder,?errorDecoder));

其中factory.create方法返回的是一个SynchronousMethodHandler对象,它的核心方法如下:

//SynchronousMethodHandler类

@Override

public?Object?invoke(Object[]?argv)?throws?Throwable?{

RequestTemplate?template?=?buildTemplateFromArgs.create(argv);

Options?options?=?findOptions(argv);

Retryer?retryer?=?this.retryer.clone();

while?(true)?{

try?{

//执行http接口调用并对返回结果进行解码

return?executeAndDecode(template,?options);

}?catch?(RetryableException?e)?{

try?{

retryer.continueOrPropagate(e);

}?catch?(RetryableException?th)?{

Throwable?cause?=?th.getCause();

if?(propagationPolicy?==?UNWRAP?&&?cause?!=?null)?{

throw?cause;

}?else?{

throw?th;

}

}

if?(logLevel?!=?Logger.Level.NONE)?{

logger.logRetry(metadata.configKey(),?logLevel);

}

continue;

}

}

}

我们调用Feign接口,最终都会交由SynchronousMethodHandler的invoke来执行。

2.2、生成Method->MethodHandler的map对象

2.1部分我们得到了以configKey为key,MethodHandler为value的map对象,我们通过反射,可以直接拿到Method对象,因此为方便查找,openfeign又生成了一个Method作为key,MethodHandler作为value的map对象:

//ReflectiveFeign类

@Override

public?<T>?T?newInstance(Target<T>?target)?{

...

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?{

methodToHandler.put(method,?nameToHandler.get(Feign.configKey(target.type(),?method)));

}

}

...

}2.3、为当前Feign接口生成代理对象

现在走到了创建Feign实例对象的最后一步,创建代理对象:

//ReflectiveFeign类

@Override

public?<T>?T?newInstance(Target<T>?target)?{

...

//ReflectiveFeign.FeignInvocationHandler类型的对象

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;

}

factory.create方法返回的是ReflectiveFeign.FeignInvocationHandler类型的对象,FeignInvocationHandler实现了InvocationHandler接口,是ReflectiveFeign的一个静态内部类,它的内部实现如下:

//?ReflectiveFeign类

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();

}

}

Proxy.newProxyInstance方法通过jdk动态代理来创建Feign接口的代理对象,当我们调用Feign实例对象的某个方法时,都会交由上面的FeignInvocationHandler对象进行处理,然后选择相应的MethodHandler,发起http接口调用。

3、小结

本节我们主要看了openfeign根据Feign接口创建Feign代理对象的过程,其实内部的逻辑还是比较简单的,无非就是解析方法上面的RequestMapping注解,提取请求接口的路径信息,还有解析接口方法的参数上的注解,只不过openfeign自己定义了一些类来处理常用的http接口信息,由于对这些类不够熟悉,所以我们初次看起来可能会觉得有些懵。希望通过本文的讲解,大家都能有所收获~

  • 发表于:
  • 原文链接https://page.om.qq.com/page/O4Qxrqu_FneOXfHAuxywoI1w0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券
http://www.vxiaotou.com