在前一篇文档中简单的描述了feignclient的实现原理,这一篇我们就将其核心原理用简单代码描述一下。
这里使用的java知识就是代理。在这篇文档中,我只是将如何构建代理的那一部分简单实现一下,为的是能够更好的理解其本质,因为spring cloud 框架帮我封装的太深以致于无法了解其本质。下面就以一个例子来简要描述一下。
接口定义
package com.test;
public interface HelloService {
String sayHello(String name);
}
为了在jvm中能够使用它,我们需要它的一个instance,而它又没有实现类,所以只能使用代理为其创建代理instance,代码如下:
代理实现
package com.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JavaProxy {
public static void main(String[] args) throws ClassNotFoundException {
JavaProxy c = new JavaProxy();
c.proxyTest();
}
private void proxyTest() throws ClassNotFoundException {
/*
* 当我们使用feignclient或者是泛型调用时根据没有HelloService的实现类,所以这个时候,需要搞到相应的InterFace
*/
try {
ClassLoader clzLoader = HelloService.class.getClassLoader();
//System.out.println(clzLoader.toString());
Class<?>[] interfaces = new Class[1];
interfaces[0] = HelloService.class;
HelloService helloService = (HelloService) Proxy.newProxyInstance(clzLoader, interfaces,
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//System.out.println("methodname is " + method.toString());
/*在这里你可以作你想作的任何事情*/
return "hello " + args[0];
}
});
String sayhello = helloService.sayHello(" world");
System.out.println(sayhello);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行代理之后 输出 hello world.
Annotation解析
因为在invoke方法中,调用的实际方法Method是知道的,此时就可以解析其上的Annotation,以及相应的参数值,构建相应的远程调用参数。此时我们可自定义Annotation,而对于Spring cloud 来说它有更好的选择,那就是使用spring mvc 的那一套Annotation ,如RequestMapping,GetMapping等(不重新发明轮子,当然我们也可以直接使用这一套Annotation)。
但是spring cloud 考虑到了性能,在系统启动时,就将注解feignclient的接口以及方法的注解全部解析了,存放在一个Map中,构建成一个Map<Method,MethodHandler>中了。在调用的时候直接使用method key,找到相应的MethodHandler,然后完成了远程调用。
关于Annotation的解析的代码,你可以当作作业试一下,将这个模型逐步完成丰富起来,最终构建自己的feign,Gook luck!