RPC系列
概述
rpc调用,我们第一反应就是引入一个接口包(api),通过接口,像调用本地方法一样实现远程调用。我们知道接口不能实例化,这就用到了java的动态代理技术。
设计模式中有代理模式,所指为静态代理,创建一个代理类,实现接口,持有被代理类的引用。在代理类的方法中调用被代理类,详细请看:wiki/Proxy_pattern#Java
动态代理是什么
相对静态代理的硬编码模式,动态代理指在运行时动态的创建出代理类及其对象。也就是说,根据服务提供商给出的api,可以动态创建他的实现类和对象。
为什么要使用动态代理
如果需要代理的类和方法越来越多,使用静态代理必然会引入同样多的的代理类,而动态代理通过固定的代码实现多接口多方法的代理,逻辑复用且解耦。
jdk动态代理示例
接口
public interface HelloService {
String sayHello();
}
代理类
public class DynamicProxyHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke 方法中处理rpc序列化、网络调用等");
return "Hello";
}
}
测试
public class HelloServiceTest {
@Test
public void testSayHello() {
HelloService helloService = (HelloService)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[] {HelloService.class},
new DynamicProxyHandler());
System.out.println("调用结果" + helloService.sayHello());
}
}
输出:
invoke 方法中处理rpc序列化、网络调用等 调用结果Hello
rpc动态代理最基本实现就是这么简单。invoke里面无法完成以下工作:协议、网络、序列化、线程模型。
有哪些动态代理技术
除了jdk自带的代理技术,主流的还有cglib、javassist、ByteBuddy(后两主要字节码操作工具)。 cglib就是封装了asm,简化了asm的操作,实现了在运行期动态生成新的class。下面使用cglib对于实现:
public class CglibDynamicProxy {
private final Enhancer enhancer = new Enhancer();
public Object newProxyInstance(Class interfaceClass) {
enhancer.setSuperclass(interfaceClass);
//设置回调实例
enhancer.setCallbacks(new MethodInterceptor[] {(o, method, objects, methodProxy) -> {
System.out.println("初始化rpc请求:" + method.getDeclaringClass().getName() + "#" + method.getName());
return "ok";
}});
return enhancer.create();
}
}
测试:
public static void main(String[] args) {
CglibDynamicProxy proxy = new CglibDynamicProxy();
HelloService helloService = (HelloService)proxy.newProxyInstance(HelloService.class);
System.out.println(helloService.sayHello());
}
jdk和cglib动态代理区别
JDK动态代理只能代理接口,而cglib可以不是接口,允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。但并不是无所不能,不能代理finel类和finel方法(因为是通过继承方式实现,但是我们知道不能继承和重新finel方法)。比如getClass(),wait()
。
http://bytebuddy.net/#/tutorial https://dzone.com/articles/cglib-missing-manual