Dubbo源码学习系列 手写简易RPC

Posted Dream_it_possible!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo源码学习系列 手写简易RPC相关的知识,希望对你有一定的参考价值。

前言

         此文为了加深对RPC的理解,运用Socket网络编程技术手写一个精简版的RPC框架。

 一、项目工程目录

二、手写服务端

           服务端主要是接收请求----> 处理请求----> 响应结果。

package com.example.rpc.server;

import com.example.rpc.api.UserInterface;
import com.example.rpc.client.Invocation;

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

public class RpcServer {


    public static void main(String[] args) {


        while (true) {
            try {
                ServerSocket serverSocket = new ServerSocket(8080);
                while (true) {
                    Socket socket = serverSocket.accept();
                    System.out.println("有新的连接过来了...");
                    ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                    try {
                        Invocation invocation = (Invocation) ois.readObject();
                        String interfaceName = invocation.getInterfaceName();
                        String methodName = invocation.getMethodName();
                        Class<?>[] paramsType = invocation.getParamsType();
                        Object[] params = invocation.getParams();
                        // 获取Class
                        Class clazz = null;
                        String tmp = UserInterface.class.getName();
                        if (interfaceName.equals(tmp)) {
                            clazz = UserInterfaceImpl.class;
                        } else {
                            throw new RuntimeException("无此接口!");
                        }
                        // 获取方法对象
                        Method method = clazz.getMethod(methodName, paramsType);
                        Object obj = method.invoke(clazz.newInstance(), params);
                        System.out.println("调用成功,结果为:" + obj);
                        // 回写结果
                        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                        oos.writeObject(obj);

                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

三、客户端

           客户端通过动态代理技术获取代理对象, 代理对象调用sayHello() 方法时,执行invoke()方法, 然后通过ois读取server返回的结果。

package com.example.rpc.client;

import com.example.rpc.api.UserInterface;
import com.example.rpc.model.User;

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

public class RpcClient {


    public static void main(String[] args) {
        // 启动客户端
        UserInterface userInterface = (UserInterface) RpcClient.getProxy(UserInterface.class);

        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String result = userInterface.sayHello("binbing!");
            System.out.println("调用成功,结果为:" + result);
        }
    }

    private static Object getProxy(Class<UserInterface> userInterfaceClass) {
        return Proxy.newProxyInstance(userInterfaceClass.getClassLoader(), new Class[]{userInterfaceClass}, (proxy, method, args) -> {
            Socket socket = new Socket("localhost", 8080);

            // 反射4要素: method  ,  接口实现类的class,  参数类型列表、参数列表。
            // 1. 给服务端发送请求,向服务端写数据
            Invocation invocation = new Invocation(userInterfaceClass.getName(), method.getName(), method.getParameterTypes(), args);
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(invocation);
            InputStream is = socket.getInputStream();
            ObjectInputStream ois = new ObjectInputStream(is);
            Object obj = ois.readObject();
            return obj;
        });
    }

}

启动服务端后,再启动客户端:

 

源码地址: https://gitee.com/bingbing-123456/rpc.git

以上是关于Dubbo源码学习系列 手写简易RPC的主要内容,如果未能解决你的问题,请参考以下文章

手写dubbo-7手撸了自定义协议远程调用服务动态扩容,梳理一下吧!

手写dubbo-6rpc调用引入注册中心实现服务动态扩容

手写模拟Dubbo实现一个自己的RPC框架

十三.Netty入门到超神系列-手撸简单版RPC框架(仿Dubbo)

手写简易RPC

手写dubbo 10-基于netty实现RPC