RMI原理及實現
簡介
RMI是遠程方法調用的簡稱,象其名稱暗示的那樣,它能夠幫助我們查找并執行遠程對象的方法。通俗地說,遠程調用就象將一個class放在A機器上,然后在B機器中調用這
個class的方法。
我個人認為,盡管RMI不是唯一的企業級遠程對象訪問方案,但它卻是最容易實現的。與能夠使不同編程語言開發的CORBA不同的是,RMI是一種純Java解決方案。在RMI
中,程序的所有部分都由Java編寫。
在看本篇文章時,我假定讀者都已經具備了較扎實的Java基礎知識,在這方面有欠缺的讀者請自行閱讀有關資料。
概念
我在前面已經提到,RMI是一種遠程方法調用機制,其過程對于最終用戶是透明的:在進行現場演示時,如果我不說它使用了RNI,其他人不可能知道調用的方法存儲在其他
機器上。當然了,二臺機器上必須都安裝有Java虛擬機(JVM)。
其他機器需要調用的對象必須被導出到遠程注冊服務器,這樣才能被其他機器調用。因此,如果機器A要調用機器B上的方法,則機器B必須將該對象導出到其遠程注冊服務器
。注冊服務器是服務器上運行的一種服務,它幫助客戶端遠程地查找和訪問服務器上的對象。一個對象只有導出來后,然后才能實現RMI包中的遠程接口。例如,如果想使機器A
中的Xyz對象能夠被遠程調用,它就必須實現遠程接口。
RMI需要使用占位程序和框架,占位程序在客戶端,框架在服務器端。在調用遠程方法時,我們無需直接面對存儲有該方法的機器。
在進行數據通訊前,還必須做一些準備工作。占位程序就象客戶端機器上的一個本機對象,它就象服務器上的對象的代理,向客戶端提供能夠被服務器調用的方法。然
后,Stub就會向服務器端的Skeleton發送方法調用,Skeleton就會在服務器端執行接收到的方法。
Stub和Skeleton之間通過遠程調用層進行相互通訊,遠程調用層遵循TCP/IP協議收發數據。下面我們來大致了解一種稱為為“綁定”的技術。
客戶端無論何時要調用服務器端的對象,你可曾想過他是如何告訴服務器他想創建什么樣的對象嗎?這正是“綁定”的的用武之地。在服務器端,我們將一個字符串變量與一個
對象聯系在一起(可以通過方法來實現),客戶端通過將那個字符串傳遞給服務器來告訴服務器它要創建的對象,這樣服務器就可以準確地知道客戶端需要使用哪一個對象了。所
有這些字符串和對象都存儲在的遠程注冊服務器中。
在編程中需要解決的問題
在研究代碼之前,我們來看看必須編寫哪些代碼:
遠程對象:這個接口只定義了一個方法。我們應當明白的是,這個接口并非總是不包括方法的代碼而只包括方法的定義。遠程對象包含要導出的每個方法的定義,它還實
現Java.rmi中的遠程接口。
遠程對象實現:這是一個實現遠程對象的類。如果實現了遠程對象,就能夠覆蓋該對象中的所有方法,因此,遠程對象的實現類將真正包含我們希望導出的方法的代碼。
遠程服務器:這是一個作為服務器使用的類,它是相對于要訪問遠程方法的客戶端而言的。它存儲著綁定的字符串和對象。
遠程客戶端:這是一個幫助我們訪問遠程方法提供幫助的類,它也是最終用戶。我們將使用查找和調用遠程方法的方法在該類中調用遠程方法。
編程
我們將首先編寫遠程對象,并將代碼保存為名字為AddServer.Java的文件:
import Java.rmi.*;
public interface AddServer extends Remote {
public int AddNumbers(int firstnumber,int secondnumber) throws RemoteException;
}
我們來看看上面的代碼。首先,為了使用其內容,我們導入rmi包。然后,我們創建一個擴展了Java.rmi中遠程接口的接口。所有的遠程對象必須擴展該遠程接口,我們將該
遠程接口稱為AddServer。在該遠程對象中,有一個名字為AddNumbers的方法,客戶端可以調用這一方法。我們必須記住的是,所有的遠程方法都需要啟
動RemoteException方法,有錯誤發生時就會調用該方法。
下面我們開始編寫遠程對象的實現。這是一個實現遠程對象并包含有所有方法代碼的類,將下面的代碼保存為名字為AddServerImpl.Java的文件:
import Java.rmi.*;
public class AddServerImpl extends UnicastRemoteObject implements AddServer {
public AddServerImpl() {
super();
}
public int AddNumbers(int firstnumber,int secondnumber) throws RemoteException {
return firstnumber + secondnumber;
}
}
首先,我們導入rmi包,然后創建一個擴展UnicastRemoteObject和實現創建的遠程對象的類;其次,我們可以為類創建一個缺省的構建器。我們還了解了AddNumbers方
法的代碼,它啟動RemoteException。這樣我們就覆蓋了創建的遠程對象中的方法。AddNumbers方法的代碼非常好理解,它接受2個整型參數,然后相加并返回它們的和。
至此,我們已經有了二個Java文件:遠程對象和遠程對象的實現。下面我們將使用Javac命令編譯這二個文件:
編譯遠程對象:
C:\jdk\bin\Javac workingdir\AddServer.Java
編譯遠程對象實現:
C:\jdk\bin\Javac workingdir\AddServerImpl.Java 這樣,就會達到二個Java文件和二個類文件,下面我們將創建stub和skeleton。為了創建stub和skeleton文件,
我們必須使用rmic編譯器編譯遠程對象實現文件。
用Rmic編譯遠程對象實現文件:
C:\jdk\bin\rmic workingdir\AddServerImpl.Java 然后,我們就會發現多了2個新建的類文件,它們分別是AddServerImpl_Stub.class
和AddServerImpl_Skel.class 。
The Coding (Contd.)
我們已經編譯了所有的源代碼,下面我們來創建客戶端和服務器端,將下面的代碼保存為名字為RmiServer.Java的文件:
import Java.rmi.*;
import Java.net.*;
public class RmiServer {
public static void main (String args[]) throws RemoteException, MalformedURLException {
AddServerImpl add = new AddServerImpl();
Naming.rebind("addnumbers",add);
}
}
首先,我們導入Java.rmi包和Java.net包。另外,我們還使用throws從句捕獲任何異常。我們從對象中得出遠程對象實現,使用rebind方法將字符串addnumbers與該對
象綁定。下面的例子顯示了綁定的含義:
從現在開始,無論何時客戶端要調用遠程對象,使用字符串addnumbers就可以實現。rebind方法有二個參數:第一個參數是字符串變量,第二個參數是遠程對象實現類的
對象。
下面我們來創建客戶端,將下面的代碼保存為名字為RmiClient.Java的文件:
import Java.rmi.*;
import Java.net.*;
public class RmiClient {
public static void main(String args[]) throws RemoteException, MalformedURLException {
String url="rmi://127.0.0.1/addnumbers";
AddServer add;
add = (AddServer)Naming.lookup(url);
int result = add.AddNumbers(10,5);
System.out.println(result);
}
}
首先,我們導入Java.rmi包和Java.net包,并使用throws從句捕獲所有必要的異常。然后通過利用Naming類中的靜態lookup方法從遠程對象中得到一個對象。(這也是我
們無需從Naming類中得到一個對象并調用它。而只使用類名字的原因。)
lookup方法接受遠程對象的完整的URL名字,該URL由完整的機器IP地址以及與對象綁定的字符串(也誻對象的綁定名)組成。在調用遠程對象時,我們使用了RMI協
議。lookup方法向我們返回一個對象,在能夠使用它前,我們必須將它的數據類型轉換為與遠程對象的數據類型一致。
Since we have both our server and client source ready, let's compile them both:
至此,我們已經有了服務器端和客戶端的源代碼,下面我們來編譯這二個源文件:
編譯遠程服務器:
C:\jdk\bin\Javac workingdir\RmiServer.Java
編譯遠程客戶端:
C:\jdk\bin\Javac workingdir\RmiClient.Java
在對我們的代碼進行測試前,還必須首先啟動RMI Registry。RMI Registry存儲有所有綁定的數據,沒有它,RMI就不能正常地運行!
啟動Rmi Registry服務器:
C:\jdk\bin\start rmiregistry
我們會注意到,這時會出現一個空白的DOS提示符窗口,這表明Rmi Registry服務器在運行,注意不要關閉該窗口。然后,我們首先在一個DOS提示符窗口中運行Rmi服務
器,然后在另一個DOS提示符窗口中運行Rmi客戶端。
啟動RMI服務器:
C:\jdk\bin\Java workingdir\RmiServer
啟動RMI客戶端:
C:\jdk\bin\Java workingdir\RmiClient
如果一切正常,我們應該能夠得到15這個輸出。我們向AddNumbers方法輸入10和5二個數字,該方法將這二者加起來,并將其和15返回給我們。如果得到了15這個輸出,
說明我們已經成功地執行了一個遠程方法。當然,在這里,我們并沒有執行真正意義上的遠程方法,因為我們的計算機既是服務器,又是客戶機。如果有計算機網絡,我們就可以
方便地進行執行遠程方法的試驗了。