最简RPC框架实现

【博文总目录>>>】|【项目源码>>>】

RPC概述

RPC(Remote Proceduce Call 远程过程调用) 一般用来实现部署在不同机器上的系统之间的方法调用,使程序能够像访问本地系统资源一样,通过网络传输过去访问远端系统资源。

RPC 调用过程

这里写图片描述
1、Client 客户端调用方法实现,负责发起RPC调用。

2、ClientStub/SereverStub 可以看作一个代理对象,屏蔽RPC调用过程中复杂的网络处理逻辑,使RPC透明化,使得调用远程方法想调用本地方法一样。

3、Server 服务端提供远程服务。

Stub 主要作用 
序列化:负责数据的序列化发序列化。 
网络传输:数据发送与接收。
注:ServerStub又叫Skeleton。

RPC 实现

远程服务接口

package mongo.rpc.service.api;

/**
 * Author: 王俊超
 * Date: 2018-02-04 10:09
 * Blog: http://blog.csdn.net/derrantcm
 * Github: https://github.com/wang-jun-chao
 * All Rights Reserved !!!
 */
public interface IHello {
    public String sayHello(String info);
}

远程服务接口实现类(Server)

package mongo.rpc.service.impl;

import mongo.rpc.service.api.IHello;

/**
 * Author: 王俊超
 * Date: 2018-02-04 10:09
 * Blog: http://blog.csdn.net/derrantcm
 * Github: https://github.com/wang-jun-chao
 * All Rights Reserved !!!
 */

public class HelloServiceImpl implements IHello {
    public String sayHello(String info) {
        String result = "hello : " + info;
        System.out.println(result);
        return result;
    }
}

3.服务器代理实现(Skeleton)

构建一个ServerSocket服务监听来自客户端的请求。

接收请求的数据。(方法名和参数)

根据请求的数据(方法名和参数),使用反射调用相应的服务。

输出服务的响应数据。

package mongo.rpc.server;

import mongo.rpc.service.api.IHello;
import mongo.rpc.service.impl.HelloServiceImpl;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 代理服务器,用于从执行代理客户端发送过来的请求
 * Author: 王俊超
 * Date: 2018-02-04 10:10
 * Blog: http://blog.csdn.net/derrantcm
 * Github: https://github.com/wang-jun-chao
 * All Rights Reserved !!!
 */
public class RpcProxyServer {
    private IHello hello = new HelloServiceImpl();

    /**
     * 启动代理服务器
     * @param port
     */
    public void publisherServer(int port) {
        try (ServerSocket ss = new ServerSocket(port)) {
            while (true) {
                // 执行代理客户端发送过来的请求,并且将请求返回
                try (Socket socket = ss.accept()) {
                    try (ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())) {
                        String method = ois.readUTF();
                        Object[] objs = (Object[]) ois.readObject();
                        Class<?>[] types = new Class[objs.length];
                        for (int i = 0; i < types.length; i++) {
                            types[i] = objs[i].getClass();
                        }
                        Method m = HelloServiceImpl.class.getMethod(method, types);
                        Object obj = m.invoke(hello, objs);

                        try (ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream())) {
                            oos.writeObject(obj);
                            oos.flush();
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

RPC 客户端代理实现(ClientStub)

构建一个Socket,连接远程服务。

向远程服务发送数据。(方法名和方法参数)

接收远程服务响应的数据。

package mongo.rpc.client;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;

/**
 * 代理客户端,用于从服务获取调用结果
 * Author: 王俊超
 * Date: 2018-02-04 10:12
 * Blog: http://blog.csdn.net/derrantcm
 * Github: https://github.com/wang-jun-chao
 * All Rights Reserved !!!
 */
public class RpcProxyClient {
    /**
     * 创建代理对象
     *
     * @param clazz 要进行代理的接口
     * @param host  服务器所在的地址
     * @param port  服务器所提供的端口
     * @param <T>   接口类
     * @return 接口的代理对象
     */
    public <T> T proxyClient(Class<T> clazz, String host, int port) {
        return (T) clazz.cast(Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {

            /**
             * 代理方法调用,用于从服务端获取调用结果
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                try (Socket socket = new Socket(host, port)) {
                    try (ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream())) {
                        oos.writeUTF(method.getName());
                        oos.writeObject(args);
                        oos.flush();

                        try (ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())) {
                            return ois.readObject();
                        }
                    }
                }
            }
        }));
    }
}

服务端发布服务

package mongo.rpc;

import mongo.rpc.server.RpcProxyServer;

/**
 * Author: 王俊超
 * Date: 2018-02-04 10:13
 * Blog: http://blog.csdn.net/derrantcm
 * Github: https://github.com/wang-jun-chao
 * All Rights Reserved !!!
 */
public class RpcServer {
    //发布服务
    public static void main(String[] args) {
        RpcProxyServer server = new RpcProxyServer();
        server.publisherServer(9999);
    }
}

客户端调用(Client)

package mongo.rpc;

import mongo.rpc.client.RpcProxyClient;
import mongo.rpc.service.api.IHello;

/**
 * Author: 王俊超
 * Date: 2018-02-04 10:14
 * Blog: http://blog.csdn.net/derrantcm
 * Github: https://github.com/wang-jun-chao
 * All Rights Reserved !!!
 */
public class RpcClient {
    // 调用服务
    public static void main(String[] args) {
        RpcProxyClient rpcClient = new RpcProxyClient();

        IHello hello = rpcClient.proxyClient(IHello.class, "localhost", 9999);
        String s = hello.sayHello("welcome to rpc");
        System.out.println(s);
    }
}

运行结果

这里写图片描述

发布了534 篇原创文章 · 获赞 1126 · 访问量 162万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览