前言
在之前的案例中,我们分析了注解扫描,加载Feign 接口信息为FactoryBean
,然后通过动态代理加载到IOC中,
在动态代理的newInstance
过程中,会使用契约Contract
创建方法元数据(MethodMetadata),然后通过这些元数据为每个执行方法加载MethodHandler
,接下来就具体分析下MethodHandler
。
MethodHandler接口
MethodHandler接口非常简单,只有一个invoke方法,和JDK中的InvocationHandler#invoke类似,应该知道JDK中的动态代理,实现InvocationHandler后,代理对象执行时,实际执行的是其invoke方法,这里MethodHandler设计就是源于此,方法执行时,实际会调用MethodHandler的invoke方法。
/**
* Like {@link InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])}, except for a single method.
*/
interface MethodHandler {
Object invoke(Object[] argv) throws Throwable;
}
MethodHandler
有两个实现类,分别为DefaultMethodHandler、SynchronousMethodHandler。
DefaultMethodHandler
是MethodHandler
的默认实现类,封装了一个MethodHandle
(JDK 7提供),MethodHandle
类的实质是将某个具体的方法映射到MethodHandle
上,通过MethodHandle
直接调用该句柄所引用的底层方法,实际就是对可执行方法的引用。但是这个只能执行目标方法,并不具备远程通信的功能。
final class DefaultMethodHandler implements MethodHandler {
private final MethodHandle unboundHandle;
private MethodHandle handle;
// 通过方法构造
// 将方法绑定到MethodHandle
public DefaultMethodHandler(Method defaultMethod) {
try {
Class<?> declaringClass = defaultMethod.getDeclaringClass();
Field field = Lookup.class.getDeclaredField("IMPL_LOOKUP");
field.setAccessible(true);
Lookup lookup = (Lookup)field.get((Object)null);
this.unboundHandle = lookup.unreflectSpecial(defaultMethod, declaringClass);
} catch (NoSuchFieldException var5) {
throw new IllegalStateException(var5);
} catch (IllegalAccessException var6) {
throw new IllegalStateException(var6);
}
}
// 将被代理的对象 绑定到MethodHandle
// bindTo方法必须在invoke方法之前调用
public void bindTo(Object proxy) {
if (this.handle != null) {
throw new IllegalStateException("Attempted to rebind a default method handler that was already bound");
} else {
this.handle = this.unboundHandle.bindTo(proxy);
}
}
// 代理对象执行时,调用目标方法
public Object invoke(Object[] argv) throws Throwable {
if (this.handle == null) {
throw new IllegalStateException("Default method handler invoked before proxy has been bound.");
} else {
// 先通过genericMethodType方法得到MethodType,再通过MethodHandle的asType转换得到新的MethodHandle,
// 最后通过新MethodHandle的invokeExact方法完成调用。
return this.handle.invokeWithArguments(argv);
}
}
}
SynchronousMethodHandler
就是同步方法处理器,可以从它的属性中看到很多涉及通信的相关类:
// 方法元数据
private final MethodMetadata metadata;
// 目标对象,默认为HardCodedTarget,
private final Target<?> target;
// 发送请求的客户端
private final Client client;
// 重试处理器
private final Retryer retryer;
// 请求拦截器
private final List<RequestInterceptor> requestInterceptors;
// 日志
private final Logger logger;
private final Level logLevel;
// 请求模板构建工厂
private final feign.RequestTemplate.Factory buildTemplateFromArgs;
// 超时配置对象
private final Options options;
private final ExceptionPropagationPolicy propagationPolicy;
// 解码器,解码响应体
private final Decoder decoder;
// 异步的响应处理器
private final AsyncResponseHandler asyncResponseHandler;
可以看到其构造方法是私有的:
所以提供了一个内部工厂类来创建实例:
可以从它的invoke
中看到,在目标对象执行时,会创建请求模板、加载配置、执行请求并进行解码,并完成重试机制。
流程分析
1. 初始化
项目启动时,创建代理对象过程中,调用的是newInstance
,在这里会为每个方法创建MethodHandler
,然后将这些Feign 接口请求方法及default 方法都绑定到创建代理对象中。
public <T> T newInstance(Target<T> target) {
// 每个对象方法,都创建一个MethodHandler,放入Map中
// OrderFeign#post(Order) -> {SynchronousMethodHandler@6141}
Map<String, MethodHandler> nameToHandler = this.targetToHandlersByName.apply(target);
// 存放执行方法 MethodHandler
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap();
// 存放接口默认default方法,不然这个接口有默认方法时,怎么执行
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList();
// 当前接口所有方法对象
Method[] var5 = target.type().getMethods();
int var6 = var5.length;
// 循环
for(int var7 = 0; var7 < var6; ++var7) {
Method method = var5[var7];
// 接口中的default 方法放入defaultMethodHandlers
// Object 中的方法不处理
// Feign 的方法,放入methodToHandler
if (method.getDeclaringClass() != Object.class) {
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
InvocationHandler handler = this.factory.create(target, methodToHandler);
// 创建代理对象
T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{
target.type()}, handler);
// 循环默认方法
Iterator var12 = defaultMethodHandlers.iterator();
// 将default 方法也绑定到代理对象中。
while(var12.hasNext()) {
DefaultMethodHandler defaultMethodHandler = (DefaultMethodHandler)var12.next();
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
创建方法执行器的实际是this.targetToHandlersByName.apply(target)
,调用的是ParseHandlersByName
的apply
方法,会获取所有方法的元数据,然后构建BuildTemplateByResolvingArgs
对象(用来创建请求模板),最后调用工厂类创建MethodHandler
。
public Map<String, MethodHandler> apply(Target target) {
// 使用契约获取方法元数据(SpringMvcContract)
List<MethodMetadata> metadata = this.contract.parseAndValidateMetadata(target.type());
Map<String, MethodHandler> result = new LinkedHashMap();
Iterator var4 = metadata.iterator();
// 循环方法元数据列表
while(var4.hasNext()) {
MethodMetadata md = (MethodMetadata)var4.next();
Object buildTemplate;
// 没有请求体 且有表单参数,说明是普通参数请求
// 请求体为x-www-form-urlencoded格式
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate = new ReflectiveFeign.BuildFormEncodedTemplateFromArgs(md, this.encoder, this.queryMapEncoder, target);
} else if (md.bodyIndex() != null) {
// 存在请求体
buildTemplate = new ReflectiveFeign.BuildEncodedTemplateFromArgs(md, this.encoder, this.queryMapEncoder, target);
} else {
// 没有请求体,也没有表单参数,走这个
buildTemplate = new ReflectiveFeign.BuildTemplateByResolvingArgs(md, this.queryMapEncoder, target);
}
// 配置了忽略
if (md.isIgnored()) {
result.put(md.configKey(), (args) -> {
throw new IllegalStateException(md.configKey() + " is not a method handled by feign");
});
} else {
// 创建方法执行器并Map 中,
result.put(md.configKey(), this.factory.create(target, md, (Factory)buildTemplate, this.options, this.decoder, this.errorDecoder));
}
}
return result;
}
}
之后调用SynchronousMethodHandler
的内部工厂类,创建对象。
public MethodHandler create(Target<?> target, MethodMetadata md, feign.RequestTemplate.Factory buildTemplateFromArgs, Options options, Decoder decoder, ErrorDecoder errorDecoder) {
return new SynchronousMethodHandler(target, this.client, this.retryer, this.requestInterceptors, this.logger, this.logLevel, md, buildTemplateFromArgs, options, decoder, errorDecoder, this.decode404, this.closeAfterDecode, this.propagationPolicy, this.forceDecoding);
}
最后创建的对象中,可以看到封装了该方法的元数据、目标对象等信息。
最终代理对象中,包含了这些方法处理器,是放在一个Map中,最后这些代理对象就被加载到了IOC中。
2. 方法执行
在Feign 接口调用时,实际执行的是代理对象(JDK 为实现了InvocationHandler接口的对象),进入的是FeignInvocationHandler
,如果不是equals、hashCode、toString等方法,则会执行this.dispatch.get(method)).invoke(args)
进行方法执行。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 不是equals、hashCode、toString
if (!"equals".equals(method.getName())) {
if ("hashCode".equals(method.getName())) {
return this.hashCode();
} else {
// 获取方法并执行
return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args);
}
} else {
try {
Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return this.equals(otherHandler);
} catch (IllegalArgumentException var5) {
return false;
}
}
}
之前我们了解过,SynchronousMethodHandler
会被放在动态代理对象的一个Map 中,所以代理代理执行时,会从Map中根据当前的执行方法拿到对象的执行器。
(MethodHandler)this.dispatch.get(method))
直接直接调用对应执行器的invoke
方法,传入的参数为当前方法的参数。
经过创建请求模板、配置、执行请求、解码,Feign 调用整个流程就结束了。