RPC

RPC

Remote Procedure Call,远程过程调用。比如 Dubbo,Java 自带的是 RMI 框架。
调用远程计算机上的服务,就像调用本地服务一样。需要服务注册中心。

制作 RPC 框架

  1. 服务端定义接口和服务实现类并且注册服务
  2. 客户端查询出服务
  3. 客户端使用动态代理调用服务
  4. 客户端代理把调用对象、方法、参数序列化成数据
  5. 客户端与服务端通过 Socket 通讯传输数据
  6. 服务端反序列化数据成对象、方法、参数
  7. 服务端代理拿到这些对象和参数后通过反射的机制调用服务的实例

服务

public interface OrderInterface {
    String order(String id);
}

public class OrderImpl implements OrderInterface {
    @Override
    public String order(String id) {
        return "调用成功:" + id;
    }
}

客户端

@Log4j
public class RPCClientFrame {
    public static <T> T getRemoteProxyObj(final Class<T> serviceInterface) {
        InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8888);
        return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(),
                new Class<?>[]{serviceInterface},
                new DynProxy(serviceInterface, address));
    }

    private static class DynProxy implements InvocationHandler {
        private final Class<?> serviceInterface;
        private final InetSocketAddress address;

        public DynProxy(Class<?> serviceInterface, InetSocketAddress address) {
            this.serviceInterface = serviceInterface;
            this.address = address;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            try (Socket socket = new Socket()) {
                socket.connect(address);
                try (ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
                     ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream())) {
                    outputStream.writeUTF(serviceInterface.getName());
                    outputStream.writeUTF(method.getName());
                    outputStream.writeObject(method.getParameterTypes());
                    outputStream.writeObject(args);
                    outputStream.flush();

                    log.info("远程调用已发送");
                    return inputStream.readObject();
                }
            }
        }
    }
}

服务端(包括注册中心)

@Log4j
public class RegisterCenter {
    private static final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
    private static final Map<String, Class<?>> serviceRegistry = new HashMap<>();
    private static boolean isRunning = false;
    @Setter
    private int port;

    public RegisterCenter(int port) {
        this.port = port;
    }

    public void register(@NotNull Class<?> serviceInterface, Class<?> impl) {
        serviceRegistry.put(serviceInterface.getName(), impl);
    }

    public void start() {
        try (ServerSocket socket = new ServerSocket()) {
            socket.bind(new InetSocketAddress(port));
            log.info("注册中心启动完毕");
            isRunning = true;
            while (!Thread.interrupted() && isRunning) {
                executor.execute(new ServiceTask(socket.accept()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void stop() {
        isRunning = false;
    }

    private static class ServiceTask implements Runnable {
        private final Socket client;

        public ServiceTask(Socket client) {
            this.client = client;
        }

        @Override
        public void run() {
            try (ObjectInputStream inputStream = new ObjectInputStream(client.getInputStream());
                 ObjectOutputStream outputStream = new ObjectOutputStream(client.getOutputStream())) {
                String serviceName = inputStream.readUTF();
                String methodName = inputStream.readUTF();
                Class<?>[] paramTypes = (Class<?>[]) inputStream.readObject();
                Object[] arguments = (Object[]) inputStream.readObject();
                Class<?> serviceClass = serviceRegistry.get(serviceName);
                Method method = serviceClass.getMethod(methodName, paramTypes);
                Object result = method.invoke(serviceClass.getConstructor().newInstance(), arguments);
                outputStream.writeObject(result);

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

服务端及注册中心启动

        RegisterCenter registerCenter = new RegisterCenter(8888);
        registerCenter.register(OrderInterface.class, OrderImpl.class);
        registerCenter.start();

客户端远程调用

        OrderInterface order = RPCClientFrame.getRemoteProxyObj(OrderInterface.class);
        log.info(order.order("123"));

相关文章:
RMI

posted @ 2021-02-03 09:46  qianbuhan  阅读(96)  评论(0)    收藏  举报