遠程方法調用(Remote Method Invocation,RMI)

背景

       遠程方法調用(Remote Method Invocation,RMI)是用Java在JDK1.1中實現的,它大大增強了Java開發分佈式應用的能力。Java作爲一種風靡一時的網絡開發語言,其巨大的威力就體現在它強大的開發分佈式網絡應用的能力上,而RMI就是開發百分之百純Java的網絡分佈式應用系統的核心解決方案之一。其實它可以被看作是RPC的Java版本。但是傳統RPC並不能很好地應用於分佈式對象系統。而Java RMI 則支持存儲於不同地址空間的程序級對象之間彼此進行通信,實現遠程對象之間的無縫遠程調用。

簡介

  遠程方法調用Remote Method InvocationRMI),像其名稱暗示的那樣,它能夠幫助我們查找並執行遠程對象的方法。通俗地說,遠程調用就像將一個class放在A機器上,然後在B機器中調用這個class的方法。儘管RMI不是唯一的企業級遠程對象訪問方案,但它卻是最容易實現的。與能夠使用不同編程語言開發的CORBA不同的是,RMI是一種純Java解決方案。在RMI中,程序的所有部分都由Java編寫。
       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語言書寫的對象進行通信。
      Java Remote Method Invocation ( RMI -- Java遠程方法調用)允許我們使用Java編寫分佈式對象。RMI可利用標準Java本機方法接口JNI與現有的和原有的系統相連接。RMI還可利用標準JDBC包與現有的關係數據庫連接。RMI/JNI和RMI/JDBC相結合,可幫助您利用RMI與目前使用非Java語言的現有服務器進行通信,而且在需要時可擴展Java在這些服務器上的使用。RMI可在擴展使用時充分利用Java的強大功能。RMI爲採用Java對象的分佈式計算提供了簡單而直接的途徑。這些對象可以是新的Java對象,也可以是圍繞現有API的簡單的Java包裝程序。
      因爲RMI是以Java爲核心的,所以,它將Java的安全性和可移植性等強大功能帶給了分佈式計算。您可將代理和業務邏輯等屬性移動到網絡中最合適的地方。如果要擴展Java在系統中的使用,RMI將使您充分利用其強大功能。

概念

  前面已經提到,RMI是一種遠程方法調用機制,其過程對於最終用戶是透明的:在進行現場演示時,如果我不說它使用了RNI,其他人不可能知道調用的方法存儲在其他機器上。當然前提是二臺機器上必須都安裝有Java虛擬機(JVM)。
  其他機器需要調用的對象必須被導出到遠程註冊服務器,這樣才能被其他機器調用。因此,如果機器A要調用機器B上的方法,則機器B必須將該對象導出到其遠程註冊服務器。註冊服務器是服務器上運行的一種服務,它幫助客戶端遠程地查找和訪問服務器上的對象。一個對象只有導出來後,然後才能實現RMI包中的遠程接口。例如,如果想使機器A中的Xyz對象能夠被遠程調用,它就必須實現遠程接口。
  RMI需要使用佔位程序和框架,佔位程序在客戶端,框架在服務器端。在調用遠程方法時,我們無需直接面對存儲有該方法的機器。
  在進行數據通訊前,還必須做一些準備工作。佔位程序就象客戶端機器上的一個本機對象,它就象服務器上的對象的代理,向客戶端提供能夠被服務器調用的方法。然後,Stub就會向服務器端的Skeleton發送方法調用,Skeleton就會在服務器端執行接收到的方法。
  Stub和Skeleton之間通過遠程調用層進行相互通訊,遠程調用層遵循TCP/IP協議收發數據。
  客戶端是通過“綁定”技術在任意時間創建並調用服務器端的對象。服務器端將一個字符串變量與一個對象聯繫在一起(通過反射機制來實現),客戶端通過將那個字符串傳遞給服務器來告訴服務器它要創建的對象,這樣服務器就可以準確地知道客戶端需要使用哪一個對象了。所有這些字符串和對象都存儲在的遠程註冊服務器中。

RMI(遠程方法調用)的原理

        方法調用從客戶端對象經佔位程序(Stub)、遠程引用層(Remote Reference Layer)和傳輸層(Transport Layer)向下,傳遞給主機,然後再次經傳輸層,向上穿過遠程調用層和框架(Skeleton),到達服務器對象。 佔位程序扮演着遠程服務器對象的代理的角色,使該對象可被客戶激活。 遠程引用層處理語義、管理單一或多重對象的通信,決定調用是應發往一個服務器還是多個。傳輸層管理實際的連接,並且追追蹤可以接受方法調用的遠程對象。服務器端的骨幹網完成對服務器對象實際的方法調用,並獲取返回值。返回值向下經遠程引用層、服務器端的傳輸層傳遞迴客戶端,再向上經傳輸層和遠程調用層返回。最後,佔位程序獲得返回值。

java軟件包java.rmi

  提供 RMI 包。RMI 指的是遠程方法調用 (Remote Method Invocation)。它是一種機制,能夠讓在某個Java 虛擬機上的對象調用另一個Java 虛擬機中的對象上的方法。可以用此方法調用的任何對象必須實現Remote該遠程接口。調用這樣一個對象時,其參數爲"marshalled" 並將其從本地虛擬機發送到遠程虛擬機(該遠程虛擬機的參數爲 "unmarshalled")上。該方法終止時,將編組來自遠程機的結果並將結果發送到調用方的虛擬機。如果方法調用導致拋出異常,則該異常將指示給調用方。

在編程中需要解決的問題

必須編寫的代碼:
  ·遠程對象(遠程服務的接口定義):這個接口只定義了一個方法。但是這個接口並非總是不包括方法的代碼而只包括方法的定義。遠程對象包含要導出的每個方法的定義,它還實現Java.rmi中的遠程接口。
  ·遠程對象實現(遠程服務接口的具體實現):這是一個實現遠程對象的類。如果實現了遠程對象,就能夠覆蓋該對象中的所有方法,因此,遠程對象的實現類將真正包含我們希望導出的方法的代碼。
  ·遠程服務器(運行遠程服務的服務器):這是一個作爲服務器使用的類,它是相對於要訪問遠程方法的客戶端而言的。它存儲着綁定的字符串和對象。
  ·遠程客戶端(需要這個遠程服務的客戶端程序):這是一個幫助我們訪問遠程方法提供幫助的類,它也是最終用戶。我們將使用查找和調用遠程方法的方法在該類中調用遠程方法。
        ·樁(Stub)和框架(Skeleton)文件
        ·一個RMI命名服務
,它允許客戶端去發現這個遠程服務
        ·類文件的提供者(一個HTTP或者FTP服務器

RMI編程步驟

要完成以上原理解決問題需要有以下幾個步驟:

  1. 生成一個遠程接口
  2. 實現遠程對象(服務器端程序)
  3. 生成佔位程序和骨幹網(服務器端程序)
  4. 編寫服務器程序
  5. 編寫客戶程序
  6. 註冊遠程對象啓動遠程對象

具體實現如下:

1、生成一個遠程接口

import java.rmi.*;
public interface PerfectTimeI extends Remote {
 long getPerfectTime() throws RemoteException;
}

2、實現遠程對象(服務器端程序)

import java.rmi.*;
import java.rmi.server.*;

public class PerfectTime extends UnicastRemoteObject implements PerfectTimeI {
	public long getPerfectTime() throws RemoteException {
		return System.currentTimeMillis();
	}

	public PerfectTime() throws RemoteException {
		super();
	}

	public static void main(String[] args) {
		System.setSecurityManager(new RMISecurityManager());
		try {
			PerfectTime pt = new PerfectTime();
			Naming.rebind("//shijin:2012/PerfectTime", pt);
			System.out.println("Ready to do time");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

3、編譯遠程對象(服務器端程序)

javac -classpath -d PerfectTime.java

 4、生成根和幹(佔位程序和骨幹程序)

rmic -classpath -d PerfectTime

5、註冊遠程對象

start rmiregistry 2012

6、啓動服務器端程序

java -D java.rmi.server.codebase=file:///d:/TestRMI/ PerfectTime

7、編寫客戶端程序

import java.rmi.*;

public class DisplayPerfectTime {
	public static void main(String[] args) {
		System.setSecurityManager(new RMISecurityManager());
		try {
			PerfectTimeI t = (PerfectTimeI) Naming
					.lookup("192.168.0.171:2005/PerfectTime");
			for (int i = 0; i < 10; i++)
				System.out.println("Perfect time =" + t.getPerfectTime());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

8、編譯客端程序

 javac -classpath . -d . DisplayPerfectTime.java

9、修改JVM的配置文件 (客戶機和服務器的都需要經過修改)

 %JRE_HOME%policytool.exe

10、啓動客戶程序

java -classpath . c15.ptime.DisplayPerfectTime

11、返回結果

Perfect time =967274884390 
Perfect time =967274884450 
Perfect time =967274884450 
Perfect time =967274884450 
Perfect time =967274884500 
Perfect time =967274884500 
Perfect time =967274884560 
Perfect time =967274884610 
Perfect time =967274884610 
Perfect time =967274884610

RMI(遠程方法調用)的優點

  從最基本的角度看,RMI是Java的遠程過程調用(RPC)機制。與傳統的RPC系統相比,RMI具有若干優點,因爲它是Java面向對象方法的一部分。傳統的RPC系統採用中性語言,所以是最普通的系統--它們不能提供所有可能的目標平臺所具有的功能。

  RMI以Java爲核心,可與採用本機方法與現有系統相連接。這就是說,RMI可採用自然、直接和功能全面的方式爲您提供分佈式計算技術,而這種技術可幫助您以不斷遞增和無縫的方式爲整個系統添加Java功能。

RMI的主要優點如下:

 面向對象:RMI可將完整的對象作爲參數和返回值進行傳遞,而不僅僅是預定義的數據類型。也就是說,您可以將類似Java哈希表這樣的複雜類型作爲一個參數進行傳遞。而在目前的RPC系統中,您只能依靠客戶機將此類對象分解成基本數據類型,然後傳遞這些數據類型,最後在服務器端重新創建哈希表。RMI則不需額外的客戶程序代碼(將對象分解成基本數據類型),直接跨網傳遞對象。

 可移動屬性:RMI可將屬性(類實現程序)從客戶機移動到服務器,或者從服務器移到客戶機。例如,您可以定義一個檢查僱員開支報告的接口,以便察看僱員是 袷亓斯灸殼笆敵械惱摺T誑Пǜ媧脣ê螅突Щ突崬臃衿鞫嘶竦檬迪指媒涌詰畝韻蟆H綣叻⑸浠衿鞫司突崢擠禱厥褂昧誦掄叩母媒涌詰牧硪桓鍪迪殖絛頡D槐卦謨沒低成習滄叭魏渦碌娜砑湍茉誑突Ф思觳橄拗鋪跫?--從而向用戶提供爍?快的反饋,並降低服務器的工作量。這樣就能具備最大的靈活性,因爲政策改變時只需要您編寫一個新的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 系統均可直接相互對話,而不必事先對協議進行轉換。

RMI與CORBA的關係

      RMI 和 CORBA 常被視爲相互競爭的技術,因爲兩者都提供對遠程分佈式對象的透明訪問。但這兩種技術實際上是相互補充的,一者的長處正好可以彌補另一者的短處。RMI 和 CORBA 的結合產生了 RMI-IIOP,RMI-IIOP 是企業服務器端 Java 開發的基礎。

      1997 年,IBM 和 Sun Microsystems啓動了一項旨在促進 Java 作爲企業開發技術的發展的合作計劃。兩家公司特別着力於如何將 Java 用作服務器端語言,生成可以結合進現有體系結構的企業級代碼。所需要的就是一種遠程傳輸技術,它兼有 Java 的 RMI(Remote Method Invocation,遠程方法調用)較少的資源佔用量和更成熟的 CORBA(Common Object Request Broker Architecture公共對象請求代理體系結構)技術的健壯性。出於這一需要,RMI-IIOP問世了,它幫助將 Java 語言推向了目前服務器端企業開發的主流語言的領先地位。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章