天天看點

手把手實作RPC架構--簡易版Dubbo構造(三)用戶端動态代理

本節commit源碼位址:416bb92

用戶端實作(動态代理)

由于在用戶端這邊我們并沒有接口的具體實作類,就沒有辦法直接生成執行個體對象。這時,我們可以通過JDK動态代理的方式生成執行個體。(關于動态代理不太熟的小夥伴可以戳:動态代理詳解)

public class RpcClientProxy implements InvocationHandler {

    private String host;
    private int port;
    
    //傳遞host和port來指明服務端的位置
    public RpcClientProxy(String host, int port){
        this.host = host;
        this.port = port;
    }

    //抑制編譯器産生警告資訊
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> clazz){
        //建立代理對象
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]{clazz}, this);
    }
}
           

InvocationHandler

接口需要實作invoke()方法,來指明代理對象的方法被調用時的動作。在這裡,我們顯然就需要生成一個RpcRequest對象,發送出去,然後把從服務端傳回的結果return即可。

@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //用戶端向服務端傳輸的對象,Builder模式生成
        RpcRequest rpcRequest = RpcRequest.builder()
                .interfaceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .parameters(args)
                .paramTypes(method.getParameterTypes())
                .build();
        //進行遠端調用的用戶端
        RpcClient rpcClient = new RpcClient();
        return ((RpcResponse)rpcClient.sendRequest(rpcRequest, host, port)).getData();
    }
           

Builder設計模式學習參考:https://blog.csdn.net/qq_38685503/article/details/113620036

具體的遠端api調用邏輯利用RpcClient對象來實作,這個對象的作用,就是将一個對象發過去,并且接受傳回的對象。

public class RpcClient {

    private static final Logger logger = LoggerFactory.getLogger(RpcClient.class);

    public Object sendRequest(RpcRequest rpcRequest, String host, int port) {
        /**
         * socket套接字實作TCP網絡傳輸
         * try()中一般放對資源的申請,若{}出現異常,()資源會自動關閉
         */
        try (Socket socket = new Socket(host, port)) {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
            objectOutputStream.writeObject(rpcRequest);
            objectOutputStream.flush();
            return objectInputStream.readObject();
        } catch (IOException | ClassNotFoundException e) {
            logger.error("調用時有錯誤發生:" + e);
            return null;
        }
    }
}
           

上面就是直接使用Java的序列化方式,通過Socket傳輸。建立一個Socket,擷取ObjectOutputStream對象,然後把需要發送的對象傳進去即可,接收時擷取ObjectInputStream對象,readObject()方法就可以獲得一個傳回的對象。Socket原理如圖:

手把手實作RPC架構--簡易版Dubbo構造(三)用戶端動态代理

本節結束……