RPC原理简析

概述

RPC(Remote Procedure Call)远程过程调用,概念就不再赘述了。个人的理解,不管是什么样的RPC框架,总体思路都是服务提供方暴露服务,消费方通过服务方提供的接口使用动态代理获取代理对象,然后调用代理对象的方法,代理对象在内部进行远程调用,获得计算结果。简要示意图如下图所示:

RPC示意图

在这个过程中,有两处关键点。第一是获取代理对象,第二是代理对象与服务提供方建立连接。对于获取代理对象的方式,需要了解Java的动态代理,可参考Java的三种代理模式。总的来说,Java的动态代理(此处只指JDK中生成代理对象的API,不包括cglib)把建立远程连接的细节封装起来,使服务消费方可以在仅已知服务提供方的接口的情况下,可以像调用本地对象的方法一样去调用远程服务。

简单实例

本实例使用socket建立连接,JDK的API做动态代理,主要有服务提供方暴露服务、服务消费方获取代理对象、代理对象与服务提供方建立远程连接并调用三个方面。忽略所有的参数校验、异常。

暴露服务

已知的某个服务的实例对象service,建立ServerSocket服务,并监听指定端口,当有远程连接建立时,创建一个线程,在线程中从输入流中依次读取方法名、参数类型、参数值等信息,并根据方法名和参数执行实例对象service中对应的方法,获得返回结果。

public class RpcExport {
    private static int port = 1234;
    /**
     * 暴露服务
     * 
     * @param service
     *            服务的实现
     * @param port
     *            服务的端口
     * @throws Exception
     */
    public static void export(final Object service) throws Exception {

        System.out.println("Export service " + service.getClass().getName() + " on port " + port);

        // 创建socket,开始监听
        ServerSocket server = new ServerSocket(port);
        while (true) {
            final Socket socket = server.accept();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    ObjectInputStream input = null;
                    ObjectOutputStream output = null;
                    try {
                        // 从监听的socket中获得输入流
                        input = new ObjectInputStream(socket.getInputStream());
                        String methodName = input.readUTF();
                        Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
                        Object[] arguments = (Object[]) input.readObject();
                        // 从监听的socket中获得输出流
                        output = new ObjectOutputStream(socket.getOutputStream());
                        Method method = service.getClass().getMethod(methodName, parameterTypes);
                        Object result = method.invoke(service, arguments);
                        output.writeObject(result);
                    } catch (Exception e) {
                    } finally {
                        try {
                            if (output != null) {
                                output.close();
                            }
                            if (input != null) {
                                input.close();
                            }
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }
}


作者:峡客
链接:https://www.jianshu.com/p/d3c7a5bbca09
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted @ 2019-12-04 10:45  西瓜皮X  阅读(316)  评论(0)    收藏  举报