RPC六-动态代理

RPC系列
1. RPC一-线程模型
2. RPC二-NettyHandler处理消息
3. RPC三-rpc协议和编解码
4. RPC四-netty异步双向责任链
5. RPC五-可靠性设计
6. RPC六-动态代理
7. 服务发现-注册中心设计

概述

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

CONTENTS