Rayson API 框架分析系列之6: 客户端动态代理原理

本系列之1: 简介
本系列之2: API服务开发
本系列之3: RSON序列化格式
本系列之4: RPC调度原理
本系列之5: NIO实现原理
本系列之6: 客户端动态代理原理👈
本系列之7: 注解处理器(APT)原理

本文介绍Rayson框架客户端使用Java动态代理技术实现RPC远程调用的原理。

Rayson框架自带Java客户端rayson.client,开发人员使用它可以简单、高效地调用使用Rayson框架所开发出来的API服务(由于Rayson框架支持多平台,因此理论上支持其他语言开发的客户端,包括浏览器和Linux命令行curl)。

正如本系列之2: API服务开发所介绍那样,使用Rayson的Java客户端调用API服务的代码示例如下:

public static void main(final String[] args) throws Exception {
    final RaysonServerAddress serverAddr = new RaysonServerAddress("localhost", 8080);
    SimpleProtocol simpleProtocol = Rayson.createProxy(serverAddr, SimpleProtocol.class);
    try {
        String echoMsg = simpleProtocol.echo("Hello World");
        System.out.println(echoMsg);
    } catch (IOException e) {
        System.err.println("Network error occurred");
    } catch (RpcException e) {
        System.err.println("Invoking RPC got logic error: error_code: " + e.getCode() + " error_message: " + e.getMessage());
    }
}

其中,第三行代码SimpleProtocol simpleProtocol = Rayson.createProxy(serverAddr, SimpleProtocol.class);会创建一个动态代理(dynamic proxy)。动态代理技术是JDK支持的技术,它利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的动态代理类及其实例(对象)。

使用JDK创建一个动态代理的示例代码如下:

java.lang.reflect.InvocationHandler handler = new MyInvocationHandler();
Foo f = (Foo) java.lang.reflect.Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler);

代码说明:

  • Foo是一个接口类型。
  • MyInvocationHandler是一个实现了接口java.lang.reflect.InvocationHandler的处理类。
  • Foo接口和处理类MyInvocationHandler的实例作为参数调用java.lang.reflect.Proxy#newProxyInstance,可以创建一个Foo接口的动态代理类,该代理是一个动态生成的Foo接口的实现类。动态代理类的字节码(Byte Codes)是JDK动态生成的。下文我们通过把动态代理类进行反编译的源代码来说明动态代理执行原理。

我们把上文Rayson客户端调用API服务示例代码中所生成的动态代理类进行反编译,其代码如下:

public final class $Proxy0 extends Proxy implements SimpleProtocol, org.rayson.api.client.Proxy {
    private static Method m3;
    private static Method m4;

    static {
        try {
            m3 = Class.forName("org.rayson.demo.simple.api.SimpleProtocol").getMethod("echo", new Class[] { Class.forName("java.lang.String") });
            m4 = Class.forName("org.rayson.demo.simple.api.SimpleProtocol").getMethod("echo2", new Class[] { Class.forName("[B") });
         } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        } catch (ClassNotFoundException e2) {
            throw new NoClassDefFoundError(e2.getMessage());
        }
    }

    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    @Override
    public final String echo(String str) throws IOException, RpcException {
        try {
            return (String) this.h.invoke(this, m3, new Object[] { str });
        } catch (IOException | Error | RuntimeException | RpcException e) {
            throw e;
        } catch (Throwable th) {
            throw new UndeclaredThrowableException(th);
        }
    }

    @Override
    public final byte[] echo2(byte[] bArr) throws IOException, RpcException {
        try {
            return (byte[]) this.h.invoke(this, m4, new Object[] { bArr });
        } catch (IOException | Error | RuntimeException | RpcException e) {
            throw e;
        } catch (Throwable th) {
            throw new UndeclaredThrowableException(th);
        }
    }
    //省略其他接口方法,其代码原理是一样的。
}

代码说明:

  • 动态代理类的名字是$Proxy0,名称是动态的。
  • 动态代理类实现了要代理的接口SimpleProtocol
  • 动态代理类把对接口SimpleProtocol的方法的调用–通过把目标方法(Method)和方法调用的参数传递给处理类–转换为对处理器实例InvocationHandler#invoke方法的调用。
  • 这样,我们就可以在处理器类的InvocationHandler#invoke方法实现中统一进行动态代理类的业务处理逻辑,看起来就像处理器类“代理了”接口SimpleProtocol实现的工作,因此这种技术就叫做动态代理技术。

Rayson客户端RPC动态代理的处理类InvocationHandler的实现代码如下:

public class RpcProxy implements InvocationHandler, Proxy {
    //省略非主要代码

    @Override
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws RpcException, IOException, ClientFilterException {
        final ClientRequestImpl request = new ClientRequestImpl(method, args);
        final ClientResponseImpl response = new ClientResponseImpl(getProtocolMirror().getMethod(request.getMethod().getName()));
        filterManager.doFilter(request, response);
        return response.getResult();
    }
}

代码说明:

  • InvocationHandler#invoke方法传递Java方法method和相应参数args作为参数,构建一个客户端请求对象request
  • 同时构建一个客户端响应对象response
  • 调用Filter Manager实例执行过滤器的过滤逻辑。关于过滤器,请参考本系列之2: API服务开发的“过滤器”部分。
  • 等待响应对象response返回结果。

这就是Rayson客户端RPC动态代理的工作原理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值