Feign封装请求基本原理(方法调用)
接上文“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. 执行结果