本節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原理如圖:
本節結束……