这个接口决定了哪些注解可以标注在接口上还是方法上是有效的,并且提取处有效的信息,组装成为MethodMetaData元信息。
1 Contract接口
public interface Contract {
// targetType:就是客户端接口的的class类型
// 此方法来解析类中链接到HTTP请求的方法:提取有效信息到元信息存储
// MethodMetadata:方法各种元信息,包括但不限于
// 返回值类型returnType
// 请求参数、请求参数的index、名称
// url、查询参数、请求body体等等等等
List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType);
}
1.2 抽象基类
abstract class BaseContract implements Contract {
@Override
public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {
// 这些检查挺有意思的
// 1、类上不能存在任何一个泛型变量
... targetType.getTypeParameters().length == 0
// 2、接口最多最多只能有一个父接口
... targetType.getInterfaces().length <= 1
targetType.getInterfaces()[0].getInterfaces().length == 0
// 对该类所有的方法进行解析:包装成一个MethodMetadata
// getMethods表示本类 + 父类的public方法
// 因为是接口,所有肯定都是public的(当然Java8支持private、default、static等)
Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
for (Method method : targetType.getMethods()) {
... // 排除掉Object的方法、static方法、default方法等
// parseAndValidateMetadata是本类的一个protected方法
MethodMetadata metadata = parseAndValidateMetadata(targetType, method);
// 请注意这个key是:metadata.configKey()
result.put(metadata.configKey(), metadata);
// 注意:这里并没有把result直接返回回去
// 而是返回一个快照版本
return new ArrayList<>(result.values());
}
}
}
可见,我们的Feign接口的是有要求的:
- 不能是泛型接口
- 接口最多只有一个父接口
会处理所有的接口方法,包含父接口的,但是不包含接口里面的默认方法, 私有方法,静态方法等,也会排除掉Object里面的方法
接下来就是对方法的元数据解析
BaseContract:
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
MethodMetadata data = new MethodMetadata();
// 方法返回类型是支持泛型的
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
// 这里使用了Feign的一个工具方法,来生成configKey,不用过于了解细节,简单的说就是尽量唯一
data.configKey(Feign.configKey(targetType, method));
// 这一步很重要:处理接口上的注解。并且处理了父接口哦
// 这就是为何你父接口上的注解,子接口里也生效的原因哦~~~
// processAnnotationOnClass()是个abstract方法,交给子类去实现(毕竟注解是可以扩展的嘛)
if (targetType.getInterfaces().length == 1) {
processAnnotationOnClass(data, targetType.getInterfaces()[0]);
}
processAnnotationOnClass(data, targetType);
// 处理标注在方法上的所有注解
// 若子接口override了父接口的方法,注解请以子接口的为主,忽略父接口方法
for (Annotation methodAnnotation : method.getAnnotations()) {
processAnnotationOnMethod(data, methodAnnotation, method);
}
// 简单的说:处理完方法上的注解后,必须已经知道到底是GET or POST 或者其它了
checkState(data.template().method() != null,
// 方法参数,支持泛型类型的。如List<String>这种...
Class<?>[] parameterTypes = method.getParameterTypes();
Type[] genericParameterTypes = method.getGenericParameterTypes();
// 注解是个二维数组...
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
int count = parameterAnnotations.length;
// 一个注解一个注解的处理
for (int i = 0; i < count; i++) {
...
// processAnnotationsOnParameter是抽象方法,子类去决定
if (parameterAnnotations[i] != null) {
isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);
}
// 方法参数若存在URI类型的参数,那url就以它为准,并不使用全局的了
if (parameterTypes[i] == URI.class) {
data.urlIndex(i);
}
...
// 校验body:
// 1、body参数不能用作form表单的parameters
// 2、Body parameters不能太多
...
return data;
}
}
其中还定义了三个抽象方法:
protected abstract void processAnnotationOnClass(MethodMetadata data, Class<?> clz);
protected abstract void processAnnotationOnMethod(MethodMetadata data,
Annotation annotation,
Method method);
protected abstract boolean processAnnotationsOnParameter(MethodMetadata data,
Annotation[] annotations,
int paramIndex);
1.3 默认实现
Feign提供的唯一实现,也是Feign的默认实现
class Default extends BaseContract {
static final Pattern REQUEST_LINE_PATTERN = Pattern.compile("^([A-Z]+)[ ]*(.*)$");
// 支持注解:@Headers
@Override
protected void processAnnotationOnClass(MethodMetadata data, Class<?> targetType) { ... }
// 支持注解:@RequestLine、@Body、@Headers
@Override
protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) { ... }
// 支持注解:@Param、@QueryMap、@HeaderMap等
@Override
protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) { ... }
...
}
后面spring-cloud为了支持让Feign支持SpringMvc的一系列接口,就是通过这个实现这个接口
我们实际对这个接口的重写还是比较少,即使重写肯定也要继承默认实现,保证Feign的原先功能不丢失。
博客内容讲述了Feign接口的约束条件,包括不能是泛型接口,接口最多只能有一个父接口。BaseContract抽象类负责解析并验证接口及方法的元数据,处理接口和方法上的注解。Default类作为默认实现,处理了@RequestLine、@Body、@Headers等注解。Spring Cloud为支持Feign与SpringMvc接口的兼容也基于此进行扩展。
167万+

被折叠的 条评论
为什么被折叠?



