简单实现RMI(远程方法调用)、代理机制

简单分析

RMI(远程方法调用)的过程:客户端与服务器同时有一套接口,但是只有服务器有实现这套接口的具体代码,客户端需要将必要的参数传送到服务器,服务器执行代码,将结果返回到客户端,一次远程方法调用结束。

编程思路

要实现这个功能我认识应该分为三部分:

  1. 接口的注册:将已有的接口注册到服务器,为了当客户端向服务器请求服务的时候,客户端能找到对应的服务运行某个方法,得到结果,返回给客户端。
  2. 服务器的建立:建立服务器。
  3. 客户端的建立:建立客户端,客户端是知道接口的。

代码实现

一:接口的注册

RpcBeanDefinition

有三个成员,并提供这三个成员的get和set方法

    private Class<?> klass;
    private Method method;
    private Object object;

RpcBeanFactory

接口的一个工厂,将注册进来的接口存储到这个工厂里面,方便客户端请求服务时获取指定服务,返回结果

    private final Map<String, RpcBeanDefinition> rpcBeanMap;

    public RpcBeanFactory() {
        rpcBeanMap = new HashMap<>();
    }

    void addRpcBean(String rpcBeanId, RpcBeanDefinition rpcBeanDefinition) {
        RpcBeanDefinition rbd = rpcBeanMap.get(rpcBeanId);
        if (rbd != null) {
            return;
        }
        rpcBeanMap.put(rpcBeanId, rpcBeanDefinition);
    }

    RpcBeanDefinition getRpcBean(String rpcBeanId) {
        return rpcBeanMap.get(rpcBeanId);
    }

RpcBeanRegistry

提供三种注册接口的方式,将传进来的接口放到Factory的Map中

    private static void doRegister(RpcBeanFactory rpcBeanFactory, Class<?> interf, Object object) {
        Method[] methods = interf.getDeclaredMethods();
        for (Method method : methods) {
            String rpcBeanId = String.valueOf(method.toString().hashCode());
            System.out.println(method.getName() + "-rpcBeanId:" + rpcBeanId);

            RpcBeanDefinition rpcBeanDefinition = new RpcBeanDefinition();
            rpcBeanDefinition.setKlass(interf);
            rpcBeanDefinition.setMethod(method);
            rpcBeanDefinition.setObject(object);

            rpcBeanFactory.addRpcBean(rpcBeanId, rpcBeanDefinition);
        }
    }

    static void registInterface(RpcBeanFactory rpcBeanFactory, Class<?> interf, Object object) {
        if (!interf.isAssignableFrom(object.getClass())) {
            return;
        }
        doRegister(rpcBeanFactory, interf, object);
    }

    static void registInterface(RpcBeanFactory rpcBeanFactory, Class<?> interf, Class<?> implementClass) {
        if (!interf.isAssignableFrom(implementClass)) {
            return;
        }
        try {
            doRegister(rpcBeanFactory, interf, implementClass.newInstance());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static void registInterface(RpcBeanFactory rpcBeanFactory, Class<?> klass) {
        try {
            doRegister(rpcBeanFactory, klass, klass.newInstance());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

二:服务器的建立

RpcServer

    private ServerSocket server;
    private int port;
    private volatile boolean goon;
    private static long executorId;
    private final RpcBeanFactory rpcBeanFactory;
    private ThreadPoolExecutor threadPool;

    public RpcServer() {
        rpcBeanFactory = new RpcBeanFactory();
        threadPool = new ThreadPoolExecutor(50, 100, 500, TimeUnit.MICROSECONDS, new LinkedBlockingDeque<>());
        this.goon = false;
    }

    public void registryRpc(Class<?> klass) {
        RpcBeanRegistry.registInterface(rpcBeanFactory, klass);
    }

    public void registryRpc(Class<?> interf, Object object) {
        RpcBeanRegistry.registInterface(rpcBeanFactory, interf, object);
    }

    public void registryRpc(Class<?> interf, Class<?> implementClass) {
        RpcBeanRegistry.registInterface(rpcBeanFactory, interf, implementClass);
    }

    public void startRpcServer() throws Exception {
        if (this.port == 0) {
            throw new PortNotDefinedException();
        }
        this.server = new ServerSocket(port);
        this.goon = true;
        new Thread(this, "RPC_SERVER").start();
    }

    @Override
    public void run() {
        while (goon) {
            try {
                Socket rpcClient = server.accept();
                new RpcServerExecutor(rpcClient, this, threadPool, ++executorId);
            } catch (IOException e) {
                goon = false;
                e.printStackTrace();
            }
        }
        stopRpcServer();
    }

RpcServerExecutor

从客户端接收id、参数,反射机制执行方法,将结果用Gson转换成字符串返回给客户端

    private Socket socket;
    private RpcServer rpcServer;
    private ThreadPoolExecutor threadPool;
    private DataInputStream dis;
    private DataOutputStream dos;

    public RpcServerExecutor(Socket socket, RpcServer rpcServer, ThreadPoolExecutor threadPool, long threadId) throws IOException {
        this.socket = socket;
        this.rpcServer = rpcServer;
        this.dis = new DataInputStream(this.socket.getInputStream());
        this.dos = new DataOutputStream(this.socket.getOutputStream());
        this.threadPool = threadPool;
        this.threadPool.execute(this);
    }

    @Override
    public void run() {
        try {
            Gson gson = (new GsonBuilder()).create();
            String rpcBeanId = dis.readUTF();
            rpcBeanId = rpcBeanId.substring(1, rpcBeanId.lastIndexOf("\""));

            RpcBeanDefinition rpcBeanDefinition = rpcServer.getRpcBeanFactory().getRpcBean(rpcBeanId);
            Method method = rpcBeanDefinition.getMethod();
            Object object = rpcBeanDefinition.getObject();

            String paraJson = dis.readUTF();
            Object[] para = gson.fromJson(paraJson, Object[].class);
            Class<?>[] parameterTypes = method.getParameterTypes();
            Object[] parameters = new Object[parameterTypes.length];
            for (int i = 0; i < para.length; i++) {
                parameters[i] = gson.fromJson(para[i] + "", parameterTypes[i]);
            }
            Object result = method.invoke(object, parameters);
            dos.writeUTF(gson.toJson(result));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            CloseableUtil.close(dis, dos, socket);
        }
    }

三、客户端的建立

ClientServer

获取代理,启动rpcExecutor

    private RpcClientExecutor rpcClientExecutor;

    public RpcClient(String rpcServerIp, int rpcServerPort) {
        this.rpcClientExecutor =
                new RpcClientExecutor(rpcServerIp, rpcServerPort);
    }

    @SuppressWarnings("unchecked")
    public <T> T jdkProxy(Class<?> klass) {
        return (T) Proxy.newProxyInstance(
                klass.getClassLoader(),
                new Class<?>[]{ klass },
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        String rpcBeanId = String.valueOf(method.toString().hashCode());
                        Class<?> returnType = method.getReturnType();
                        return rpcClientExecutor.rpcExecutor(rpcBeanId, args, returnType);
                    }
                }
        );
    }

RpcClientExecutor

将methodId跟参数数组发到服务器端,得到服务器端传过来的结果

    private String rpcServerIp;
    private int rpcServerPort;
    
    public RpcClientExecutor(String rpcServerIp, int rpcServerPort) {
        this.rpcServerIp = rpcServerIp;
        this.rpcServerPort = rpcServerPort;
    }

    @SuppressWarnings("unchecked")
    <T> T rpcExecutor(String rpcBeanId, Object[] parameters, Class<?> returnType) throws  Exception {
        Socket socket = new Socket(rpcServerIp, rpcServerPort);
        Gson gson = (new GsonBuilder()).create();

        System.out.println("rpcBeanId:" + gson.toJson(rpcBeanId));
        System.out.println("parameters:" + gson.toJson(parameters));
        DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
        dos.writeUTF(gson.toJson(rpcBeanId));
        dos.writeUTF(gson.toJson(parameters));

        DataInputStream dis = new DataInputStream(socket.getInputStream());
        String str = dis.readUTF();
        Object result = gson.fromJson(str, returnType);
        CloseableUtil.close(dos, dis, socket);
        return (T)result;
    }

测试

测试接口

public interface IUserAction {
    UserModel getUserById(String id);
    UserModel getUser(UserModel user);
    UserModel getUser(UserModel user, UserModel user2);
    List<UserModel> getUserList();
}

接口实现

    @Override
    public UserModel getUserById(String id) {
        UserModel user = new UserModel();
        user.setId(id);
        user.setName("张三");
        user.setSex(true);

        return user;
    }

    @Override
    public List<UserModel> getUserList() {
        List<UserModel> userList = new ArrayList<>();

        UserModel user = new UserModel();
        user.setId("12345678");
        user.setName("张三");
        user.setSex(true);
        userList.add(user);

        user = new UserModel();
        user.setId("87654321");
        user.setName("李四");
        user.setSex(false);
        userList.add(user);

        return userList;
    }

    @Override
    public UserModel getUser(UserModel user) {
        return user;
    }

    @Override
    public UserModel getUser(UserModel user, UserModel user2) {
        System.out.println("userModel:" + user);
        return null;
    }

UserModel


	private String id;
	private String name;
	private boolean sex;
	private UserModel next;
	

ClientTest

    public static void main(String[] args) {
        RpcClient rpcClient = new RpcClient("127.0.0.1", 54189);

        IUserAction proxy = rpcClient.jdkProxy(IUserAction.class);
        UserModel user2 = new UserModel();
        user2.setName("哈哈哈");
        UserModel user = new UserModel();
        user.setName("哈哈哈");
        user2.setNext(user);
        UserModel model = proxy.getUser(user2, user2);
        System.out.println(model);
    }

ServerTest

    public static void main(String[] args) {
        RpcServer rpcServer = new RpcServer();
        rpcServer.setPort(54189);
        rpcServer.registryRpc(IUserAction.class, UserActionImpl.class);
        try {
            rpcServer.startRpcServer();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

结果

parameters:[{"name":"哈哈哈","sex":false,"next":{"name":"哈哈哈","sex":false}},{"name":"哈哈哈","sex":false,"next":{"name":"哈哈哈","sex":false}}]
null

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值