摘要:我要學好分布式通信框架技術我要學好分布式分布式框架是最近幾年的熱門。先寫個測試用的遠程接口,注意接口要拋異常實現遠程接口,并且繼承創建服務器程序方法注冊遠程對象創建客戶端程序調用過程流程去注冊中心注冊,端啟動服務。
title: 我要學好分布式-RMI通信框架
date: 2018-07-26 19:28:30
分布式框架是最近幾年的熱門。可是要想理解分布式框架著實不易,為了努力跟上時代潮流,特此開了一個專題,起名“我要學好分布式”,通過博客來分享一下我的學習過程,加深我對分布式整體框架的理解。
想要解鎖更多新姿勢?請訪問我的博客
什么是RPC英文就不說了。中文名遠程進程調用協議。顧名思義,客戶端在不知道細節的情況下,可以調用遠程計算機的api,就像是調用本地方法一樣。
RPC協議是一個規范。主流的PRC協議有Dubbo、Thrif、RMI、Webservice、Hessain
他又一個非常大的特點,網絡協議和網絡IO對于調用端和服務端來說是透明的(動態代理)
一個RPC框架包含的要素:
RMIRMI(remote method invocation) ?, 可以認為是RPC的java版本
RMI使用的是JRMP(Java Remote Messageing Protocol), JRMP是專門為java定制的通信協議,所以他是純java的分布式解決方案 。注意,這個RMI已經老舊過時了。
RMI Demo先寫個測試用的遠程接口,注意接口要拋異常
public interface ISayHello extends Remote { public String satHello(String name) throws RemoteException; }
? 2.實現遠程接口,并且繼承:UnicastRemoteObject
public class SayHelloImpl extends UnicastRemoteObject implements ISayHello{ protected SayHelloImpl() throws RemoteException { } public String satHello(String name) throws RemoteException { return "hello," + name; } }
? 3.創建服務器程序: createRegistry方法注冊遠程對象
import java.net.MalformedURLException; import java.rmi.AlreadyBoundException; import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; public class HelloServer { public static void main(String[] args) { try { ISayHello sayHello =new SayHelloImpl(); LocateRegistry.createRegistry(8888); Naming.bind("rmi://localhost:8888/sayhello",sayHello); System.out.println("server start success"); } catch (RemoteException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (AlreadyBoundException e) { e.printStackTrace(); } }
? 4.創建客戶端程序
public class HelloClient { public static void main(String[] args) { try { ISayHello iSayHello = (ISayHello) Naming.lookup("rmi://localhost:8888/sayhello"); System.out.println("hello"); } catch (NotBoundException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } } }RMI調用過程
流程:
1.去注冊中心注冊,server端啟動服務。
2.注冊中心聯系stub(存根)。stub用于客戶端 ,在j2ee中是這么說的:為屏蔽客戶調用遠程主機上的對象,必須提供某種方式來模擬本地對象,這種本地對象稱為存根(stub),存根負責接收本地方法調用,并將它們委派給各自的具體實現對象
3.server注冊對象,然后返回注冊對象
4.客戶端訪問注冊中心,(動態代理)返回stub對象
5.stub(存根)遠程調用skeleton (骨架 )
6.skeleton 調用相應接口
源碼讓我看看核心的注冊服務的源碼實現
public RegistryImpl(final int var1) throws RemoteException { this.bindings = new Hashtable(101); //安全認證 if (var1 == 1099 && System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction() { public Void run() throws RemoteException { LiveRef var1x = new LiveRef(RegistryImpl.id, var1); RegistryImpl.this.setup(new UnicastServerRef(var1x, (var0) -> { return RegistryImpl.registryFilter(var0); })); return null; } }, (AccessControlContext)null, new SocketPermission("localhost:" + var1, "listen,accept")); } catch (PrivilegedActionException var3) { throw (RemoteException)var3.getException(); } } else { //初始化遠程引用UnicastServerRef對象 LiveRef var2 = new LiveRef(id, var1);//《-------------------------- this.setup(new UnicastServerRef(var2, RegistryImpl::registryFilter)); } }
點進UnicastServerRef,找出實現的關系~
點進setup方法,用idea反編碼
public Remote exportObject(Remote var1, Object var2, boolean var3) throws RemoteException { Class var4 = var1.getClass(); Remote var5; try { var5 = Util.createProxy(var4, this.getClientRef(), this.forceStubUse);//《-------------------- } catch (IllegalArgumentException var7) { throw new ExportException("remote object implements illegal remote interface", var7); } if (var5 instanceof RemoteStub) {//《-------------------------- this.setSkeleton(var1); } Target var6 = new Target(var1, this, var5, this.ref.getObjID(), var3);//《------------------------ this.ref.exportObject(var6); this.hashToMethod_Map = (Map)hashToMethod_Maps.get(var4); return var5; }
發現在創建代理,判斷當前的var是不是遠程stub,如果是就設置骨架。如果不是,就構建target對象。點開代理
public static Remote createProxy(Class> var0, RemoteRef var1, boolean var2) throws StubNotFoundException { Class var3; try { var3 = getRemoteClass(var0);//《-------------------------- } catch (ClassNotFoundException var9) { throw new StubNotFoundException("object does not implement a remote interface: " + var0.getName()); } if (var2 || !ignoreStubClasses && stubClassExists(var3)) { return createStub(var3, var1);//《-------------------------- } else { final ClassLoader var4 = var0.getClassLoader(); final Class[] var5 = getRemoteInterfaces(var0); final RemoteObjectInvocationHandler var6 = new RemoteObjectInvocationHandler(var1); try { return (Remote)AccessController.doPrivileged(new PrivilegedAction() { public Remote run() { return (Remote)Proxy.newProxyInstance(var4, var5, var6); } }); } catch (IllegalArgumentException var8) { throw new StubNotFoundException("unable to create proxy", var8); } } }
發現在調用遠程服務,然后創建了stub。繼續點開getRemoteClass()方法
private static Class> getRemoteClass(Class> var0) throws ClassNotFoundException { while(var0 != null) { Class[] var1 = var0.getInterfaces();//《-------------------------- for(int var2 = var1.length - 1; var2 >= 0; --var2) { if (Remote.class.isAssignableFrom(var1[var2])) { return var0; } } var0 = var0.getSuperclass(); } throw new ClassNotFoundException("class does not implement java.rmi.Remote"); }
發現現在在創建實例
好吧,回到createProxy方法,再看看順著往下走,看看Target var6 = new Target(var1, this, var5, this.ref.getObjID(), var3);
`this.ref.exportObject(var6);`的出口對象方法
public void exportObject(Target var1) throws RemoteException { this.ep.exportObject(var1); }
public interface Endpoint { Channel getChannel(); void exportObject(Target var1) throws RemoteException; Transport getInboundTransport(); Transport getOutboundTransport(); }
public void exportObject(Target var1) throws RemoteException { this.transport.exportObject(var1); }
一路點下去,找到了tcp出口的方法。這是屬于協議層的玩意。
public void exportObject(Target var1) throws RemoteException { synchronized(this) { this.listen(); ++this.exportCount; }
一路點下去,發現listen。
private void listen() throws RemoteException { assert Thread.holdsLock(this); TCPEndpoint var1 = this.getEndpoint(); int var2 = var1.getPort(); if (this.server == null) { if (tcpLog.isLoggable(Log.BRIEF)) { tcpLog.log(Log.BRIEF, "(port " + var2 + ") create server socket"); } try { this.server = var1.newServerSocket();//《-------------------------- Thread var3 = (Thread)AccessController.doPrivileged(new NewThreadAction(new TCPTransport.AcceptLoop(this.server), "TCP Accept-" + var2, true)); var3.start(); } catch (BindException var4) { throw new ExportException("Port already in use: " + var2, var4); } catch (IOException var5) { throw new ExportException("Listen failed on port: " + var2, var5); } } else { SecurityManager var6 = System.getSecurityManager(); if (var6 != null) { var6.checkListen(var2); } }
發現newServerSocket!!!
綜上,總體流程和上圖一樣。
RMI缺陷1.基于java,支持語言單一
2.服務注冊只能注冊到我上面分析的那個源碼。注冊中心掛了以后就完了
3.序列化是用java原生那個方法,效率不好
4.服務端底層是bio方式,性能不好
手寫RMI步驟:
編寫服務器程序,暴露一個監聽, 可以使用socket
編寫客戶端程序,通過ip和端口連接到指定的服務器,并且將數據做封裝(序列化)
服務器端收到請求,先反序列化。再進行業務邏輯處理。把返回結果序列化返回
源碼:https://github.com/tengshe789...
把源碼發布到GitHub了,在把源碼粘貼太麻煩了。
結束
此片完了~ 想要了解更多精彩新姿勢?請訪問我的個人博客 .
本篇為原創內容,已在個人博客率先發表,隨后CSDN,segmentfault,juejin同步發出。如有雷同,緣分呢兄弟。趕快加個好友~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76629.html
摘要:微軟的雖然引入了事件機制,可以在隊列收到消息時觸發事件,通知訂閱者。由微軟作為主要貢獻者的,則對以及做了進一層包裝,并能夠很好地實現這一模式。 在分布式服務框架中,一個最基礎的問題就是遠程服務是怎么通訊的,在Java領域中有很多可實現遠程通訊的技術,例如:RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS等,這些名詞之間到底是些什么關系呢,它們背后到底是基...
摘要:微軟的雖然引入了事件機制,可以在隊列收到消息時觸發事件,通知訂閱者。由微軟作為主要貢獻者的,則對以及做了進一層包裝,并能夠很好地實現這一模式。 在分布式服務框架中,一個最基礎的問題就是遠程服務是怎么通訊的,在Java領域中有很多可實現遠程通訊的技術,例如:RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS等,這些名詞之間到底是些什么關系呢,它們背后到底是基...
摘要:對于與而言,則可以看做是消息傳遞技術的一種衍生或封裝。在生產者通知消費者時,傳遞的往往是消息或事件,而非生產者自身。通過消息路由,我們可以配置路由規則指定消息傳遞的路徑,以及指定具體的消費者消費對應的生產者。采用和來進行遠程對象的通訊。 消息模式 歸根結底,企業應用系統就是對數據的處理,而對于一個擁有多個子系統的企業應用系統而言,它的基礎支撐無疑就是對消息的處理。與對象不同,消息本質上...
摘要:具體可以參考消息隊列之具體可以參考實戰之快速入門十分鐘入門阿里中間件團隊博客是一個分布式的可分區的可復制的基于發布訂閱的消息系統主要用于大數據領域當然在分布式系統中也有應用。目前市面上流行的消息隊列就是阿里借鑒的原理用開發而得。 我自己總結的Java學習的系統知識點以及面試問題,目前已經開源,會一直完善下去,歡迎建議和指導歡迎Star: https://github.com/Snail...
摘要:都是分開部署,單獨上線的。序列化畢竟是遠程通信,需要將對象轉化成二進制流進行傳輸。服務化架構的演進架構當業務規模很小時,將所有功能都不熟在同一個進程中,通過雙機或者負載均衡器實現負債分流此時,分離前后臺邏輯的架構是關鍵。 showImg(https://segmentfault.com/img/bVbiI2F?w=2250&h=1500); 前言 為什么需要RPC,而不是簡單的HTTP...
閱讀 725·2021-11-17 09:33
閱讀 3757·2021-09-01 10:46
閱讀 1751·2019-08-30 11:02
閱讀 3280·2019-08-29 15:05
閱讀 1396·2019-08-26 11:39
閱讀 2272·2019-08-23 17:04
閱讀 1973·2019-08-23 15:43
閱讀 1371·2019-08-23 14:12