自行實現一個簡單的RMI
阿新 • • 發佈:2018-12-18
在教主的帶領下,完成了一個很簡單的RMI工具。就當是練習網路程式設計吧。
RMI(Remote Method Invocation),遠端方法呼叫。
涉及兩個網路端。其核心思想是,一個端可以通過呼叫另一個端的方法,實現相關功能。 一個端“執行”一個方法,而這個方法的實際執行是在另一端進行的!
要進行遠端方法呼叫,那麼,兩個端都應該有相同的類,相同的方法。一個端執行一個方法,其實本質是通過呼叫這個類的代理物件的方法,在其中攔截這個方法,將這個方法的雜湊值和引數,通過網路通訊傳輸給另一端;另一端根據雜湊值和引數,能唯一的確定到那個方法,執行完成後將結果返回給對端。
我採用的是短連線,jdk代理。
大致的處理流程:
我的思路:
建立RPC伺服器端:
主要有兩個大的步驟:
1、需要給RpcBeanFactory注入方法的雜湊值和方法引數(這兩個資料相同,就能保證客戶機準確的呼叫遠端方法)。
注入的具體分析:
static void doRegist(RpcBeanFactory rpcBeanFactory, Class<?> interfaces, Object object) { Method[] methods = interfaces.getDeclaredMethods(); for (Method method : methods) { String rpcBeanId = String.valueOf(method.toString().hashCode()); RpcBeanDefination rpcBeanDefination = new RpcBeanDefination(); rpcBeanDefination.setKlass(interfaces); rpcBeanDefination.setMethod(method); rpcBeanDefination.setObject(object); rpcBeanFactory.AddRpcBean(rpcBeanId, rpcBeanDefination); } }
通過傳過來的介面,得到這個介面中的所有方法,遍歷,把每個方法的資訊都注入到RpcBeanFactory的Map中。
2、RpcServer需要一直偵聽客戶機的請求,如果有請求,那麼RpcServerExecutor進行具體的處理。
分析:
@Override public void run() { try { // 接收Rpc客戶端傳遞的rpcBeanId和引數 String rpcBeanId = ois.readUTF(); Object[] parameters = (Object[]) ois.readObject(); showParameters(parameters); // 定位相關類,物件和方法 RpcBeanDefination rpcBeanDefination; rpcBeanDefination = rpcServer.getRpcBeanFactory().getRpcBean(rpcBeanId); // 執行Rpc客戶端要求執行的方法 Method method = rpcBeanDefination.getMethod(); Object object = rpcBeanDefination.getObject(); Object result = method.invoke(object, parameters); // 向客戶端返回執行結果 oos.writeObject(result); } catch (IOException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { closeSocket(); } }
這是RpcServerExecutor中的處理,接收->定位->執行->返回結果。
建立RPC客戶機端:
1、在代理物件的方法中,呼叫RpcClientExecutor。
/*jdk代理*/
public Object getProxy(Class<?> klass) {
// 判斷klass是否是介面,若不是,則應該採用cglib代理模式
return Proxy.newProxyInstance(klass.getClassLoader(), new Class<?>[] { klass }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String rpcBeanId = String.valueOf(method.toString().hashCode());
Object result = rpcClientExecutor.rpcExecutor(rpcBeanId, args);
return result;
}
});
}
給方法生成雜湊值,呼叫rpcExecutor。
2、執行RpcClientExecutor。
<T> T rpcExecutor(String rpcBeanId, Object[] para) throws IOException, ClassNotFoundException {
Socket socket = new Socket(rpcServerIp, rpcServerPort);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
// 給RPC伺服器傳送rpcBeanId和引數
oos.writeUTF(rpcBeanId);
oos.writeObject(para);
// 接收RPC伺服器執行的結果,並返回
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Object result = ois.readObject();
closeSocket(ois, oos, socket);
return (T) result;
}
客戶端處理很簡單:傳送資訊->接收資訊。