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("登錄成功了"));
    }
}

實例執行結果

服務端執行進入等待

客戶端執行

再看服務端變化

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