徒手打造 - RPC遠程通訊框架v1

手寫RPC框架V1

gitee地址:https://gitee.com/kylin1991_admin/rpc_handwriting

Api.jar

1、寫一個IHelloService接口,類似dubbo
public interface IHelloService {
   String sayHello(String context);
 }
2、一個RpcRequest請求模型
@Data
public class RpcRequest implements Serializable {
    private String className;
    private String methodName;
    private Object[] parameters;
}

Server

1、Server 服務註冊
  public class Server {
      public static void main(String[] args) {
          IHelloService helloService = new IHelloServiceImpl();
          RpcProxyServer rpcProxyServer = new RpcProxyServer(helloService,8080);
          rpcProxyServer.publisher();
      }
  }
2、RpcProxyServer 服務發佈
public class RpcProxyServer {
    private Object service;
    private int port;

    public RpcProxyServer(Object service, int port) {
        this.service = service;
        this.port = port;
    }

    public void publisher() {
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            while (true) {
                Socket socket = serverSocket.accept();
                executor.execute(new ProcessorHandler(service,socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static final Executor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),
            Runtime.getRuntime().availableProcessors(),
            60L,
            TimeUnit.MINUTES,
            new ArrayBlockingQueue<>(Runtime.getRuntime().availableProcessors()),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy()
    );
}
3、請求處理ProcessorHandler
public class ProcessorHandler implements Runnable {
    private Object service;
    private Socket socket;

    public ProcessorHandler(Object service, Socket socket) {
        this.service = service;
        this.socket = socket;
    }

    @Override
    public void run() {
        try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
             ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream())) {

            // 接受請求
            RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject();

            // 反射調用並且返回結果
            objectOutputStream.writeObject(invoke(rpcRequest));
            objectOutputStream.flush();


        } catch (IOException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private Object invoke(RpcRequest rpcRequest, Object service) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class clazz = Class.forName(rpcRequest.getClassName());
        Class<?>[] parametersTypes = new Class<?>[rpcRequest.getParameters().length];
        for (int i = 0; i < parametersTypes.length; i++) {
            parametersTypes[i] = rpcRequest.getParameters()[i].getClass();
        }
        Method method = clazz.getMethod(rpcRequest.getMethodName(), parametersTypes);
        return method.invoke(service, rpcRequest.getParameters());
    }
}

Client

1、Client 發起請求
public class Client {
    public static void main(String[] args) {
        RpcProxyClient rpcProxyClient = new RpcProxyClient();
        IHelloService helloService = rpcProxyClient.proxyClient(IHelloService.class,"localhost",8080);
        System.out.println(helloService.sayHello("lilei"));;
    }
}
2、遠程調用(採用jdk動態代理)
  • RpcProxyClient
public class RpcProxyClient {
    public <T> T proxyClient(Class<?> interfacesCls, String host, int port) {
        return (T) Proxy.newProxyInstance(
                interfacesCls.getClassLoader(),
                new Class<?>[]{interfacesCls},
                new RemoteInvocationHandler(host,port));
    }
}
  • RemoteInvocationHandler 用於遠程方法調用
public class RemoteInvocationHandler implements InvocationHandler {
    private String host;
    private int port;

    public RemoteInvocationHandler(String host, int port) {
        this.host = host;
        this.port = port;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //包裝請求
        RpcRequest rpcRequest = new RpcRequest();
        rpcRequest.setClassName(method.getDeclaringClass().getName());
        rpcRequest.setMethodName(method.getName());
        rpcRequest.setParameters(args);

        //發送請求,並且獲得結果
        RpcNetTransport rpcNetTransport = new RpcNetTransport(host, port);
        return rpcNetTransport.send(rpcRequest);
    }
}
3、RpcNetTransport 調用
public class RpcNetTransport {
    private String host;
    private int port;

    public RpcNetTransport(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public Object send(RpcRequest rpcRequest) {
        Object result = null;
        try (Socket socket = new Socket(host, port);
             ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
             ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream())) {

            objectOutputStream.writeObject(rpcRequest);
            objectOutputStream.flush();

            result = objectInputStream.readObject();

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return result;
    }
}

測試

1、啓動Server

2、啓動Client

測試成功!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章