今天继续学习feign,feign从使用上来说非常简单,就是spring的常用使用方法,开启feign功能,使用feign注解就可以了,那今天就看看怎么开启的,如何运行的。
组件分析
既然是从@EnableFeignClients开始使用的,那就从这个注解说起,这个注解向容器导入了FeignClientsRegistrar这个组件,那就来看看这个组件。
这样看来这就是个ImportBeanDefinitionRegistrar,用来注册bean定义的,那都注册哪些bean定义呢?
细看其实现,就是扫描就是扫描特定包的被@FeignClient标注的类,然后向容器中注册FeignClientFactoryBean,看下这个bean。
这样看来,这个bean就是个FactoryBean,看到这里,处于对spring容器的了解,应该看看其如何创建bean的了。
其构建过程还是相对复杂的,因为要涉及许多其它组件,如Client(LoadBalancerFeignClient)、Targeter(DEfaultTargeter)、Contract、Encoder、Decoder、InvocationHandlerFactory、Capability等,但总体说来就是通过Feign.Builder来构建Feign,进而获取FeignClient动态代理对象的过程,下面看看具体实现类的主要实现ReflectiveFeign。
public <T> T newInstance(Target<T> target) {
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;
}
从这里能看出来,就是jdk动态代理的构建过程,只不过其InvocationHandler处理了一下,看其invoke方法
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);
}
也就是从dispatch,取得方法然后执行,而这个dispatch就是那个Map(methodTohandler),也就是说在feignClient哪个方法被调用的时候,就从这个map里取出对应的MethodHandler去执行,看其具体的实现SynchronousMethodHandler,就会通过客户端Client去处理请求。
总结
这里只是简单说了下FeignClient的创建,通过FactoryBean来扩展,通过动态代理来构建代理bean,代理bean的调用处理器InvocationHandler只是到其Map中去找到具体方法处理器去执行。那简单说就是对接口(FeignClient)进行动态代理,进而实现http请求的调用处理。
附简单流程图。