动手实现一个简单的RPC框架

    RPC(Remote Procedure Call,远程过程调用)一般用来实现部署在不同机器上的系统之间的方法调用,是的程序能够像访问本地资源一样,通过网络传输去访问远端系统资源。RPC框架实现的架构原理都是类似的,如下图所示。

                

    Client Code:客户端调用方代码,负责发起RPC调用,为调用方提供接口

    Serialization:负责对RPC调用通过网络传输的内容进行序列化和反序列化

    Stub Proxy:一个代理对象,屏蔽RPC调用过程中复杂的网络处理逻辑

    Transport:作为RPC框架底层的通信传输模块,一般通过Socket在客户端和服务器端进行信息交互

    Server Code:服务端服务业务逻辑具体的实现

下面就开始吧。

    首先编写Client Code,也就是调用方的接口

package Caller;

public interface ProductService {
    public Product queryById(long id);
}

    一个很简的接口,通过id进行查询商品

    接下来是商品本身:

package Caller;

import java.io.Serializable;

public class Product implements Serializable {
    private long id;
    private String name;
    private double price;
    /**
     * get/set方法
     **/
    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

    因为使用的是Java的原生序列化,所以需要实现Serializable接口。

    接下来是客户端的实现,我把客户端的实现和代理写在一块了。

public class ProductCaller {
    public static void main(String[] args) {
        ProductService service = (ProductService) rpc(ProductService.class);
        Product product = service.queryById(100);
        System.out.println(product);
    }
    private static Object rpc(Class<?> clazz) {
        return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                ObjectOutputStream oos = null;
                ObjectInputStream ois = null;
                Socket socket = null;
                try {
                    socket = new Socket("localhost",8777);
                    oos = new ObjectOutputStream(socket.getOutputStream());
                    //发送调用方法的一些属性
                    oos.writeUTF(clazz.getName());
                    oos.writeUTF(method.getName());
                    oos.writeObject(method.getParameterTypes());
                    oos.writeObject(args);
                    //等待服务端的结果
                    ois = new ObjectInputStream(socket.getInputStream());
                    return ois.readObject();
                }finally {
                    if (oos!=null){
                        try {
                            oos.close();
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                    if (ois!=null){
                        try {
                            ois.close();
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                    if (socket!=null){
                        try {
                            socket.close();
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
    }
}

    可以看到,给服务端发送了类的全路径名,方法名,方法的参数类型,方法的实参,并等待服务端的执行结果

    服务端的实现,首先是业务逻辑的实现

public class ProductServiceImpl implements ProductService{
    @Override
    public Product queryById(long id) {
        Product product = new Product();
        product.setId(id);
        product.setName("张三");
        product.setPrice(1.0);
        return product;
    }
}

    其次是服务端的实现

public class ProductServer {
    private static final Map<String,Class<?>> map = new HashMap<>();
    static {
        map.put("Caller.ProductService",ProductServiceImpl.class);
    }
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8777);
            Socket socket = serverSocket.accept();
            //读取信息
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            String ClassName = ois.readUTF();
            String methodName = ois.readUTF();
            Class[] paramterTypes = (Class[]) ois.readObject();
            Object[] paramters = (Object[]) ois.readObject();
            Class<?> clazz = map.get(ClassName);
            if (clazz==null)
                throw new Exception("not found "+ClassName);
            Method method = clazz.getMethod(methodName,paramterTypes);
            Object result = method.invoke(clazz.newInstance(), paramters);
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(result);
            oos.close();
            ois.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

    服务端接收客户端的请求,并进行反序列化得到相应的属性,然后使用反射执行方法并返回结果。

    让我们运行一下,先启动服务端,再启动客户端,结果如下:


    好了,一个简单的RPC框架以及完成。

在以上代码中有可以改进的方法:

    比如使用NIO或者Netty进行通信

    使用Json字符串或者一个序列化性能高的工具

猜你喜欢

转载自blog.csdn.net/yanghan1222/article/details/80456455