前言
在之前,我们了解到Feign 基于接口声明,生成执行请求的动态代理对象,那么究竟是如何将接口上的注解等信息,解析的呢?这里就必须了解Feign 中非常重要的一个接口Contract
。
Contract
意为契约,实际就是Feign 中的接口解析器,会解析接口方法上的注解为元数据,以此来创建请求模板及方法执行器。
MethodMetadata
MethodMetadata
意为方法元数据,可以理解为一个Java Bean,Feign 会解析接口的每个方法,封装为MethodMetadata
,并依据这个创建方法处理器。
// 键名=》OrderFeign#post(Order)
private String configKey;
// 方法返回类型=》Order
private transient Type returnType;
// 请求url位置
private Integer urlIndex;
// 请求体位置
private Integer bodyIndex;
// 消息头位置
private Integer headerMapIndex;
// queryMap位置
private Integer queryMapIndex;
private boolean queryMapEncoded;
// 请求体类型
private transient Type bodyType;
// 请求模板
private final RequestTemplate template = new RequestTemplate();
private final List<String> formParams = new ArrayList();
private final Map<Integer, Collection<String>> indexToName = new LinkedHashMap();
private final Map<Integer, Class<? extends Expander>> indexToExpanderClass = new LinkedHashMap();
private final Map<Integer, Boolean> indexToEncoded = new LinkedHashMap();
private transient Map<Integer, Expander> indexToExpander;
private BitSet parameterToIgnore = new BitSet();
// 是否忽略该方法
private boolean ignored;
// 需要代理的接口类型
private transient Class<?> targetType;
// 接口中的方法 =》public abstract pojo.Order account.OrderFeign.post(pojo.Order)
private transient Method method;
// 警告级别
private final transient List<String> warnings = new ArrayList();
Contract 接口及其实现类
Contract
接口只有一个方法,parseAndValidateMetadata
(解析并校验元数据),转入一个Class类型,将其解析为MethodMetadata
。
public interface Contract {
List<MethodMetadata> parseAndValidateMetadata(Class<?> var1);
}
BaseContract
是Contract 的抽象类,实现了其parseAndValidateMetadata
方法,它的解析方法中,会解析接口上的所有方法(包含父类接口)为MethodMetadata
,但不包含Object、静态、默认等方法。
SpringMvcContract
提供了基于Spring MVC注解的解析,可以解析@RequestMapping
注解,当然衍生的@GetMapping
也是可以的。
加载流程源码解析
1. 进入动态代理
在项目启动,创建动态代理对象时,会调用Contract
进行方法解析,这里可以看到这里为SpringMvcContract
,也可以看到SpringMvcContract
中有很多解析器,可以解析很多Spring MVC的注解。
注解参数处理器AnnotatedParameterProcessor
有如下实现类,分别对应了解析@MatrixVariable、@PathVariable、@SpringQueryMap、@RequestHeader、@RequestParam、@RequestPart等Spring MVC 提供的注解。
2. 进入解析
接着调用到SpringMvcContract的arseAndValidateMetadata(Class<?>
targetType)方法,会查询当前接口及父接口中的方法,并循环这些方法,依次处理解析,最终放入到Map中(eg: {" OrderFeign#post(Order)","MethodMetadata"}),
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
// 检查泛型,说明Feign 接口,不能添加泛型
Util.checkState(targetType.getTypeParameters().length == 0, "Parameterized types unsupported: %s", new Object[]{
targetType.getSimpleName()});
// 检查继承的接口,说明最多只能有一个父接口
Util.checkState(targetType.getInterfaces().length <= 1, "Only single inheritance supported: %s", new Object[]{
targetType.getSimpleName()});
if (targetType.getInterfaces().length == 1) {
// 有父接口时,再检查是父接口是否有父接口,说明父接口必须是顶级接口
Util.checkState(targetType.getInterfaces()[0].getInterfaces().length == 0, "Only single-level inheritance supported: %s", new Object[]{
targetType.getSimpleName()});
}
Map<String, MethodMetadata> result = new LinkedHashMap();
// 获取接口上的所有方法
Method[] var3 = targetType.getMethods();
int var4 = var3.length;
// 循环方法
for(int var5 = 0; var5 < var4; ++var5) {
Method method = var3[var5];
// 不是Object 上的方法、不是static、不是default 方法(接口),则会进入解析
if (method.getDeclaringClass() != Object.class && (method.getModifiers() & 8) == 0 && !Util.isDefault(method)) {
// 调用parseAndValidateMetadata解析
MethodMetadata metadata = this.parseAndValidateMetadata(targetType, method);
Util.checkState(!result.containsKey(metadata.configKey()), "Overrides unsupported: %s", new Object[]{
metadata.configKey()});
// 放入到Map 中 OrderFeign#post(Order)=》
result.put(metadata.configKey(), metadata);
}
}
return new ArrayList(result.values());
}
依次处理解析进入到parseAndValidateMetadata(Class<?> targetType, Method method)
方法,该方法会对 @RequestMapping
注解中的配置属性进行解析,比如produces、consumes等。
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
// 已处理的方法
this.processedMethods.put(Feign.configKey(targetType, method), method);
// 调用parseAndValidateMetadata
MethodMetadata md = super.parseAndValidateMetadata(targetType, method);
// 查询 RequestMapping 注解,并解析属性。
RequestMapping classAnnotation = (RequestMapping)AnnotatedElementUtils.findMergedAnnotation(targetType, RequestMapping.class);
if (classAnnotation != null) {
if (!md.template().headers().containsKey("Accept")) {
this.parseProduces(md, method, classAnnotation);
}
if (!md.template().headers().containsKey("Content-Type")) {
this.parseConsumes(md, method, classAnnotation);
}
this.parseHeaders(md, method, classAnnotation);
}
return md;
}
在对@RequestMapping
注解进行属性解析之前,会进入到parseAndValidateMetadata(Class<?> targetType, Method method)
方法进行注解解析,这个是主要的解析方法,会完成方法上注解、形参注解的解析:
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
MethodMetadata data = new MethodMetadata();
data.targetType(targetType); // 接口类型
data.method(method); // 方法 public abstract java.util.List account.OrderFeign.insertOrder(java.lang.Long,java.lang.String,java.lang.Long,java.lang.Long)
// 方法返回类型
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
// 生产OrderFeign#insertOrder(Long,String,Long,Long)
data.configKey(Feign.configKey(targetType, method));
if (targetType.getInterfaces().length == 1) {
// 获取父类中的注解并处理
this.processAnnotationOnClass(data, targetType.getInterfaces()[0]);
}
// 处理@RequestMapping 注解
this.processAnnotationOnClass(data, targetType);
// 获取方法上的所有注解,这里是@GetMapping
Annotation[] var4 = method.getAnnotations();
int var5 = var4.length;
for(int var6 = 0; var6 < var5; ++var6) {
Annotation methodAnnotation = var4[var6];
// 处理Spring MVC 注解,RequestMapping、GetMapping等,将请求方式,路径设置到模板中,
// 注解中的headers、consumes、headers 都会被添加到请求模板中
// 因为 GetMapping也是RequestMapping,所以这里会被解析到
this.processAnnotationOnMethod(data, methodAnnotation, method);
}
// 配置了忽略,则直接跳过
if (data.isIgnored()) {
return data;
} else {
// 检查请求方式
Util.checkState(data.template().method() != null, "Method %s not annotated with HTTP method type (ex. GET, POST)%s", new Object[]{
data.configKey(), data.warnings()});
// 所有参数的类型
Class<?>[] parameterTypes = method.getParameterTypes();
Type[] genericParameterTypes = method.getGenericParameterTypes();
// 获取参数注解
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
// 参数的长度
int count = parameterAnnotations.length;
for(int i = 0; i < count; ++i) {
// 是否配置了Spring MVC 的参数注解,比如@RequestParam
boolean isHttpAnnotation = false;
if (parameterAnnotations[i] != null) {
// 处理形参,添加到请求模板中。
isHttpAnnotation = this.processAnnotationsOnParameter(data, parameterAnnotations[i], i);
}
// 设置该序号的参数也被处理
if (isHttpAnnotation) {
data.ignoreParamater(i);
}
// 校验参数是否是 URI类型
if (parameterTypes[i] == URI.class) {
data.urlIndex(i);
} else if (!isHttpAnnotation && parameterTypes[i] != Options.class) {
// 如果不是 RequestParam\Map 类型的参数,则会解析为请求体。
if (!data.isAlreadyProcessed(i)) {
Util.checkState(data.formParams().isEmpty(), "Body parameters cannot be used with form parameters.%s", new Object[]{
data.warnings()});
Util.checkState(data.bodyIndex() == null, "Method has too many Body parameters: %s%s", new Object[]{
method, data.warnings()});
data.bodyIndex(i);
data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i]));
} else {
Util.checkState(data.formParams().isEmpty() || data.bodyIndex() == null, "Body parameters cannot be used with form parameters.%s", new Object[]{
data.warnings()});
}
}
}
// 处理 @HeaderMap
if (data.headerMapIndex() != null) {
checkMapString("HeaderMap", parameterTypes[data.headerMapIndex()], genericParameterTypes[data.headerMapIndex()]);
}
// 处理@QueryMap
if (data.queryMapIndex() != null && Map.class.isAssignableFrom(parameterTypes[data.queryMapIndex()])) {
checkMapKeys("QueryMap", genericParameterTypes[data.queryMapIndex()]);
}
return data;
}
}
其中processAnnotationOnClass
用于处理@RequestMapping
注解,将注解中的访问URL地址设置到请求模板中。
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
if (clz.getInterfaces().length == 0) {
// 获取RequestMapping 注解
RequestMapping classAnnotation = (RequestMapping)AnnotatedElementUtils.findMergedAnnotation(clz, RequestMapping.class);
if (classAnnotation != null && classAnnotation.value().length > 0) {
String pathValue = Util.emptyToNull(classAnnotation.value()[0]);
pathValue = this.resolve(pathValue);
if (!pathValue.startsWith("/")) {
pathValue = "/" + pathValue;
}
data.template().uri(pathValue);
}
}
}
processAnnotationsOnParameter
则用于处理方法上的参数注解:
protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) {
boolean isHttpAnnotation = false;
// 创建AnnotatedParameterContext
AnnotatedParameterContext context = new SpringMvcContract.SimpleAnnotatedParameterContext(data, paramIndex);
Method method = (Method)this.processedMethods.get(data.configKey());
Annotation[] var7 = annotations;
int var8 = annotations.length;
// 循环形参
for(int var9 = 0; var9 < var8; ++var9) {
Annotation parameterAnnotation = var7[var9];
// 处理形参,将@RequestParam 中方法的参数,添加到请求模板中。
AnnotatedParameterProcessor processor = (AnnotatedParameterProcessor)this.annotatedArgumentProcessors.get(parameterAnnotation.annotationType());
if (processor != null) {
Annotation processParameterAnnotation = this.synthesizeWithMethodParameterNameAsFallbackValue(parameterAnnotation, method, paramIndex);
isHttpAnnotation |= processor.processArgument(context, processParameterAnnotation, method);
}
}
// 处理Multipart 表单数据
if (!this.isMultipartFormData(data) && isHttpAnnotation && data.indexToExpander().get(paramIndex) == null) {
TypeDescriptor typeDescriptor = createTypeDescriptor(method, paramIndex);
if (this.conversionService.canConvert(typeDescriptor, STRING_TYPE_DESCRIPTOR)) {
Expander expander = this.convertingExpanderFactory.getExpander(typeDescriptor);
if (expander != null) {
data.indexToExpander().put(paramIndex, expander);
}
}
}
return isHttpAnnotation;
}
最终,这个接口中的所有就被解析为了元数据,最终会依据这些信息创建方法处理器及请求模板。
循环方法元数据,创建方法处理器。