JAVA实现PRC基本调用

什么是PRC

PRC是一种远程过程调用协议,可以像调用本地服务一样调用远程的服务,是一种采用客户端/服务器的模式。常见的PRC框架也有很多比如最常用的dubbo等。

RPC能够让本地应用简单、高效地调用远程服务器中的服务。它主要应用在分布式系统、微服务。

代码实例

技术点:Java socket、动态代理、Java对象操作流、反射

接口以及接口实现

/**
 * Created by IntelliJ IDEA.
 * 服务类接口
 */
public interface IService {
    String getTest(String string);
}

/**
 * Created by IntelliJ IDEA.
 * 服务接口的实现类
 */
public class ServiceImpl implements IService {

    @Override
    public String getTest(String string) {
       return "调用成功了: " + string;
    }
}

/**
 * Created by IntelliJ IDEA.
 */
public interface ILoginService {
    String login(String string);
}

/**
 * Created by IntelliJ IDEA.
 */
public class LoginServiceImpl implements ILoginService {
    @Override
    public String login(String string) {
        return string;
    }
}

服务端服务注册实例

/**
 * Created by IntelliJ IDEA.
 * 服务端
 */
public class RpcServer {
    private static final HashMap<String, Class<?>> SERVER_MAP = new HashMap<>();
    private int port;

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

    /**
     * serviceInterface : 接口
     * impl:接口实现类
     * 将接口服务放到一个HashMap集合中
     */
    public RpcServer register(HashMap<Class<?>, Class<?>> hashMap) {
        hashMap.forEach((key, value) -> SERVER_MAP.put(key.getName(), value));
        return this;
    }

    /**
     * 执行等待
     *
     */
    public void run() throws IOException {

        ServerSocket server = new ServerSocket();
        /*打开服务端并设置端口为port*/
        server.bind(new InetSocketAddress(port));
        /*对象输入流*/
        ObjectInputStream input = null;
        /*对象输出流*/
        ObjectOutputStream output = null;
        Socket socket = null;
        try {
            while (true) {
                /*开始接收 线程会进行等待*/
                socket = server.accept();
                /*输入流 获取到客户端发送来的消息*/
                input = new ObjectInputStream(socket.getInputStream());
                String serviceName = input.readUTF();
                System.out.println("服务名称:" + serviceName);
                String methodName = input.readUTF();
                System.out.println("服务方法" + methodName);
                /*服务的参数列表*/
                Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
                /*接口的Class*/
                Object[] arguments = (Object[]) input.readObject();
                /*根据服务名称得到该服务的实现类*/
                Class serviceClass = SERVER_MAP.get(serviceName);
                if (serviceClass == null) {
                    throw new ClassNotFoundException(serviceName + " not found");
                }
                /*得到方法*/
                Method method = serviceClass.getMethod(methodName, parameterTypes);
                /*相当于接口回调*/
                Object result = method.invoke(serviceClass.newInstance(), arguments);
                /*输出流*/
                output = new ObjectOutputStream(socket.getOutputStream());
                /*发送*/
                output.writeObject(result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    public static void main(String[] args) throws IOException {
        HashMap<Class<?>, Class<?>> hashMap = new HashMap<>();
        hashMap.put(IService.class, ServiceImpl.class);
        hashMap.put(ILoginService.class, LoginServiceImpl.class);
        /*服务端开始注册服务*/
        new RpcServer(7777).register(hashMap).run();
    }
}

客户端服务调用实例

/**
 * Created by IntelliJ IDEA.
 * 动态代理
 * 客户端调用服务
 */
public class RpcClient<T> implements InvocationHandler {

    private Class<T> serviceInterface;
    private InetSocketAddress addr;

    /**
     * serviceInterface:远程服务接口
     * ip:远程IP地址
     * port:远程端口
     */
    public RpcClient(Class<T> serviceInterface, String ip, String port) {
        this.serviceInterface = serviceInterface;
        this.addr = new InetSocketAddress(ip, Integer.parseInt(port));
    }

    public T getClientIntance() {
        /*传入被代理的类*/
        return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface}, this);
    }

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

        Socket socket = null;
        ObjectOutputStream output = null;
        ObjectInputStream input = null;

        try {
            /*创建Socket客户端,根据指定地址连接远程服务提供者*/
            socket = new Socket();
            /*连接服务端*/
            socket.connect(addr);
            /*将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者*/
            output = new ObjectOutputStream(socket.getOutputStream());
            output.writeUTF(serviceInterface.getName());
            output.writeUTF(method.getName());
            output.writeObject(method.getParameterTypes());
            output.writeObject(args);

            /*同步阻塞等待服务器返回应答,获取应答后返回*/
            input = new ObjectInputStream(socket.getInputStream());
            /*返回结果*/
            return input.readObject();
        } finally {
            if (socket != null) {
                socket.close();
            }
            if (output != null) {
                output.close();
            }
            if (input != null) {
                input.close();
            }
        }
    }

    public static void main(String[] args) {
        RpcClient client = new RpcClient<>(IService.class, "localhost", "7777");
        IService hello = (IService) client.getClientIntance();
        /*调用成功 打印返回值*/
        System.out.println(hello.getTest("RPC"));

        RpcClient loginPrcClient = new RpcClient<>(ILoginService.class, "localhost", "7777");
        ILoginService iLoginService = (ILoginService) loginPrcClient.getClientIntance();
        /*调用成功 打印返回值*/
        System.out.println(iLoginService.login("登录成功了"));
    }
}

实例执行结果

服务端执行进入等待

客户端执行

再看服务端变化

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