1. 程式人生 > >dubbo相關知識(六)-- java RMI框架

dubbo相關知識(六)-- java RMI框架

1、概述

在 Java 世界裡,有一種技術可以實現“跨虛擬機器”的呼叫,它就是 RMI(Remote Method Invocation,遠端方法呼叫),通過RMI技術,某一個本地的JVM可以呼叫存在於另外一個JVM中的物件方法,就好像它僅僅是在呼叫本地JVM中某個物件方法一樣。

RMI中,只要一個類extends了java.rmi.Remote介面,即可成為存在於伺服器端的遠端物件,供客戶端訪問並提供一定的服務。同時,遠端物件必須實現java.rmi.server.UniCastRemoteObject類,這樣才能保證客戶端訪問獲得遠端物件時,該遠端物件將會把自身的一個拷貝以Socket的形式傳輸給客戶端,此時客戶端所獲得的這個拷貝稱為“存根”,而伺服器端本身已存在的遠端物件則稱之為“骨架”。其實此時的存根是客戶端的一個代理,用於與伺服器端的通訊,而骨架也可認為是伺服器端的一個代理,用於接收客戶端的請求之後呼叫遠端方法來響應客戶端的請求。 

RMI 框架的基本原理大概如下圖,應用了代理模式來封裝了本地存根與真實的遠端物件進行通訊的細節。

2,RMI使用場景

RMI是基於JAVA語言的,也就是說在RMI技術框架的描述中,只有Server端使用的是JAVA語言並且Client端也是用的JAVA語言,才能使用RMI技術

RMI適用於兩個系統都主要使用JAVA語言進行構造,不需要考慮跨語言支援的情況。並且對兩個JAVA系統的通訊速度有要求的情況。

RMI 是一個良好的、特殊的RPC實現:使用JRMP協議承載資料描述,可以使用BIO和NIO兩種IO通訊模型。RMI框架是可以在大規模集群系統中使用的,當然是不是使用RMI技術,還要看您的產品的技術背景、團隊的技術背景、公司的業務背景甚至客戶的非技術背景等。在分散式系統中,我們使用 RMI 技術可輕鬆將 服務提供者(Service Provider)與 服務消費者(Service Consumer)進行分離,充分體現元件之間的弱耦合,系統架構更易於擴充套件。其實它可以被看作是RPC的Java版本。但是傳統RPC並不能很好地應用於分散式物件系統。而Java RMI 則支援儲存於不同地址空間的程式級物件之間彼此進行通訊,實現遠端物件之間的無縫遠端呼叫。RMI目前使用Java遠端訊息交換協議JRMP(Java Remote Messaging Protocol)進行通訊。由於JRMP是專為Java物件制定的,Java RMI具有Java的"Write Once,Run Anywhere"的優點,是分散式應用系統的百分之百純Java解決方案。用Java RMI開發的應用系統可以部署在任何支援JRE(Java Run Environment Java,執行環境)的平臺上。但由於JRMP是專為Java物件制定的,因此,RMI對於用非Java語言開發的應用系統的支援不足。不能與用非Java語言書寫的物件進行通訊。

3,RMI框架的基本組成

雖然RMI早在JDK.1.1版本中就開放了。但是在JDK1.5的版本中RMI又進行改進。所以我們後續的程式碼示例和原理講解都基於最新的RMI框架特性。

要定義和使用一套基於RMI框架工作的系統,您至少需要做一下幾個工作:

1、定義RMI Remote介面 
2、實現這個RMI Remote介面 
3、生成Stub(樁)和 Skeleton(骨架)。這一步的具體操作視不同的JDK版本而有所不同(例如JDK1.5後,Skeleton不需要手動);“RMI登錄檔”的工作方式也會影響“Stub是否需要命令列生成”這個問題。 
4、向“RMI登錄檔”註冊在第2步我們實現的RMI Remote介面。 
5、建立一個Remote客戶端,通過java“命名服務”在“RMI登錄檔”所在的IP:PORT尋找註冊好的RMI服務。 
6、Remote客戶端向呼叫存在於本地JVM中物件那樣,呼叫存在於遠端JVM上的RMI介面。

下圖描述了上述幾個概念名稱間的關係,呈現了JDK.5中RMI框架其中一種執行方式(注意,是其中一種工作方式。也就是說RMI框架不一定都是這種執行方式,後文中我們還將描述另外一種RMI的工作方式):

這裡寫圖片描述


JDK中的RMI框架在JDK1.1、JDK1.2、JDK1.5、JDK1.6+幾個版本中做了較大的調整。以下我們討論的RMI工作原理都是基於JDK1.6+版本的。

4、JAVA RMI 工作原理

RMI(遠端方法呼叫)原理示意圖 


原理示意圖 方法呼叫從客戶物件經佔位程式(Stub)、遠端引用層(Remote Reference Layer)和傳輸層(Transport Layer)向下,傳遞給主機,然後再次經傳 輸層,向上穿過遠端呼叫層和骨幹網(Skeleton),到達伺服器物件。 佔位程式扮演著遠端伺服器物件的代理的角色,使該物件可被客戶啟用。 遠端引用層處理語義、管理單一或多重物件的通訊,決定呼叫是應發往一個伺服器還是多個。傳輸層管理實際的連線,並且追蹤可以接受方法呼叫的遠端物件。伺服器端的骨幹網完成對伺服器物件實際的方法呼叫,並獲取返回值。返回值向下經遠端引用層、伺服器端的傳輸層傳遞迴客戶端,再向上經傳輸層和遠端呼叫層返回。最後,佔位程式獲得返回值。 
要完成以上步驟需要有以下幾個步驟: 
1、 生成一個遠端介面 
2、 實現遠端物件(伺服器端程式)
3、 生成佔位程式和骨幹網(伺服器端程式)
4、 編寫伺服器程式 
5、 編寫客戶程式 
6、 註冊遠端物件 
7、 啟動遠端物件

下面我們來講解一下RMI的基本原理。本人翻閱網上的眾多RMI資料基本上程式碼都是一大抄(甚至變數名、語法錯誤都一樣),還有很多資料存在誤導讀者的情況。下圖描述了整個RMI框架的幾個核心概念:

這裡寫圖片描述

五、RMI(遠端方法呼叫)的優點 

從最基本的角度看,RMI是Java的遠端過程呼叫(RPC)機制。與傳統的RPC系統相比,RMI具有若干優點,因為它是Java面向物件方法的一部分。傳統的RPC系統採用中性語言,所以是最普通的系統--它們不能提供所有可能的目標平臺所具有的功能。 
RMI以Java為核心,可與採用本機方法與現有系統相連線。這就是說,RMI可採用自然、直接和功能全面的方式為您提供分散式計算技術,而這種技術可幫助您以不斷遞增和無縫的方式為整個系統新增Java功能。
RMI的主要優點如下: 
面向物件:RMI可將完整的物件作為引數和返回值進行傳遞,而不僅僅是預定義的資料型別。也就是說,您可以將類似Java雜湊表這樣的複雜型別作為一個引數進行傳遞。而在目前的RPC系統中,您只能依靠客戶機將此類物件分解成基本資料型別,然後傳遞這些資料型別,最後在伺服器端重新建立雜湊表。RMI則不需額外的客戶程式程式碼(將物件分解成基本資料型別),直接跨網傳遞物件。 
可移動屬性:RMI可將屬性(類實現程式)從客戶機移動到伺服器,或者從伺服器移到客戶機。這樣就能具備最大的靈活性,因為政策改變時只需要您編寫一個新的Java類,並將其在伺服器主機上安裝一次即可。 
設計方式:物件傳遞功能使您可以在分散式計算中充分利用面向物件技術的強大功能,如二層和三層結構系統。如果您能夠傳遞屬性,那麼您就可以在您的解決方案中使用面向物件的設計方式。所有面向物件的設計方式無不依靠不同的屬性來發揮功能,如果不能傳遞完整的物件--包括實現和型別--就會失去設計方式上所提供的優點。 
安  全:RMI使用Java內建的安全機制保證下載執行程式時使用者系統的安全。RMI使用專門為保護系統免遭惡意小應用程式侵害而設計的安全管理程式,可保護您的系統和網路免遭潛在的惡意下載程式的破壞。在情況嚴重時,伺服器可拒絕下載任何執行程式。 
便於編寫和使用:RMI使得Java遠端服務程式和訪問這些服務程式的Java客戶程式的編寫工作變得輕鬆、簡單。遠端介面實際上就是Java介面。服務程式大約用三行指令宣佈本身是服務程式,其它方面則與任何其它Java物件類似。這種簡單方法便於快速編寫完整的分散式物件系統的服務程式,並快速地製做軟體的原型和早期版本,以便於進行測試和評估。因為RMI程式編寫簡單,所以維護也簡單。 
可連線現有/原有的系統:RMI可通過Java的本機方法介面JNI與現有系統進行進行互動。利用RMI和JNI,您就能用Java語言編寫客戶端程式,還能使用現有的伺服器端程式。在使用RMI/JNI與現有伺服器連線時,您可以有選擇地用Java重新編寫服務程式的任何部分,並使新的程式充分發揮Java的功能。類似地,RMI可利用JDBC、在不修改使用資料庫的現有非Java原始碼的前提下與現有關係資料庫進行互動。 
編寫一次,到處執行:RMI是Java“編寫一次,到處執行 ”方法的一部分。任何基於RMI的系統均可100%地移植到任何Java虛擬機器上,RMI/JDBC系統也不例外。如果使用RMI/JNI與現有系統進行互動工作,則採用JNI編寫的程式碼可與任何Java虛擬機器進行編譯、執行。 
分散式垃圾收集:RMI採用其分散式垃圾收集功能收集不再被網路中任何客戶程式所引用的遠端服務物件。與Java 虛擬機器內部的垃圾收集類似,分散式垃圾收集功能允許使用者根據自己的需要定義伺服器物件,並且明確這些物件在不再被客戶機引用時會被刪除。 
平行計算:RMI採用多執行緒處理方法,可使您的伺服器利用這些Java執行緒更好地並行處理客戶端的請求。Java分散式計算解決方案:RMI從JDK 1.1開始就是Java平臺的核心部分,因此,它存在於任何一臺1.1 Java虛擬機器中。所有RMI系統均採用相同的公開協議,所以,所有Java 系統均可直接相互對話,而不必事先對協議進行轉換。