RMI簡(jiǎn)要開發(fā)
簡(jiǎn)介RMI是遠(yuǎn)程方法調(diào)用的簡(jiǎn)稱,象其名稱暗示的那樣,它能夠幫助我們查找并執(zhí)行遠(yuǎn)程對(duì)象的方法。通俗地說(shuō),遠(yuǎn)程調(diào)用就象將一個(gè)class放在A機(jī)器上,然后在B機(jī)器中調(diào)用這個(gè)class的方法。
我個(gè)人認(rèn)為,盡管RMI不是唯一的企業(yè)級(jí)遠(yuǎn)程對(duì)象訪問(wèn)方案,但它卻是最容易實(shí)現(xiàn)的。與能夠使不同編程語(yǔ)言開發(fā)的CORBA不同的是,RMI是一種純Java解決方案。在RMI中,程序的所有部分都由Java編寫。
在看本篇文章時(shí),我假定讀者都已經(jīng)具備了較扎實(shí)的Java基礎(chǔ)知識(shí),在這方面有欠缺的讀者請(qǐng)自行閱讀有關(guān)資料。
概念
我在前面已經(jīng)提到,RMI是一種遠(yuǎn)程方法調(diào)用機(jī)制,其過(guò)程對(duì)于最終用戶是透明的:在進(jìn)行現(xiàn)場(chǎng)演示時(shí),如果我不說(shuō)它使用了RNI,其他人不可能知道調(diào)用的方法存儲(chǔ)在其他機(jī)器上。當(dāng)然了,二臺(tái)機(jī)器上必須都安裝有Java虛擬機(jī)(JVM)。
其他機(jī)器需要調(diào)用的對(duì)象必須被導(dǎo)出到遠(yuǎn)程注冊(cè)服 務(wù)器,這樣才能被其他機(jī)器調(diào)用。因此,如果機(jī)器A要調(diào)用機(jī)器B上的方法,則機(jī)器B必須將該對(duì)象導(dǎo)出到其遠(yuǎn)程注冊(cè)服務(wù)器。注冊(cè)服務(wù)器是服務(wù)器上運(yùn)行的一種服 務(wù),它幫助客戶端遠(yuǎn)程地查找和訪問(wèn)服務(wù)器上的對(duì)象。一個(gè)對(duì)象只有導(dǎo)出來(lái)后,然后才能實(shí)現(xiàn)RMI包中的遠(yuǎn)程接口。例如,如果想使機(jī)器A中的Xyz對(duì)象能夠被 遠(yuǎn)程調(diào)用,它就必須實(shí)現(xiàn)遠(yuǎn)程接口。
RMI需要使用占位程序和框架,占位程序在客戶端,框架在服務(wù)器端。在調(diào)用遠(yuǎn)程方法時(shí),我們無(wú)需直接面對(duì)存儲(chǔ)有該方法的機(jī)器。
在進(jìn)行數(shù)據(jù)通訊前,還必須做一些準(zhǔn)備工作。占位程序就象客戶端機(jī)器上的一個(gè)本機(jī)對(duì)象,它就象服務(wù)器上的對(duì)象的代理,向客戶端提供能夠被服務(wù)器調(diào)用的方法。然后,Stub就會(huì)向服務(wù)器端的Skeleton發(fā)送方法調(diào)用,Skeleton就會(huì)在服務(wù)器端執(zhí)行接收到的方法。
Stub和Skeleton之間通過(guò)遠(yuǎn)程調(diào)用層進(jìn)行相互通訊,遠(yuǎn)程調(diào)用層遵循TCP/IP協(xié)議收發(fā)數(shù)據(jù)。下面我們來(lái)大致了解一種稱為為“綁定”的技術(shù)。
客戶端無(wú)論何時(shí)要調(diào)用服務(wù)器端的對(duì)象,你可曾想過(guò)他是如何告訴服務(wù)器他想創(chuàng)建什么樣的對(duì)象嗎?這正是“綁定”的的用武之地。在服務(wù)器端,我們將一個(gè)字符 串變量與一個(gè)對(duì)象聯(lián)系在一起(可以通過(guò)方法來(lái)實(shí)現(xiàn)),客戶端通過(guò)將那個(gè)字符串傳遞給服務(wù)器來(lái)告訴服務(wù)器它要?jiǎng)?chuàng)建的對(duì)象,這樣服務(wù)器就可以準(zhǔn)確地知道客戶端 需要使用哪一個(gè)對(duì)象了。所有這些字符串和對(duì)象都存儲(chǔ)在的遠(yuǎn)程注冊(cè)服務(wù)器中。
在編程中需要解決的問(wèn)題
在研究代碼之前,我們來(lái)看看必須編寫哪些代碼:
·遠(yuǎn)程對(duì)象:這個(gè)接口只定義了一個(gè)方法。我們應(yīng)當(dāng)明白的是,這個(gè)接口并非總是不包括方法的代碼而只包括方法的定義。遠(yuǎn)程對(duì)象包含要導(dǎo)出的每個(gè)方法的定義,它還實(shí)現(xiàn)Java.rmi中的遠(yuǎn)程接口。
·遠(yuǎn)程對(duì)象實(shí)現(xiàn):這是一個(gè)實(shí)現(xiàn)遠(yuǎn)程對(duì)象的類。如果實(shí)現(xiàn)了遠(yuǎn)程對(duì)象,就能夠覆蓋該對(duì)象中的所有方法,因此,遠(yuǎn)程對(duì)象的實(shí)現(xiàn)類將真正包含我們希望導(dǎo)出的方法的代碼。
·遠(yuǎn)程服務(wù)器:這是一個(gè)作為服務(wù)器使用的類,它是相對(duì)于要訪問(wèn)遠(yuǎn)程方法的客戶端而言的。它存儲(chǔ)著綁定的字符串和對(duì)象。
·遠(yuǎn)程客戶端:這是一個(gè)幫助我們?cè)L問(wèn)遠(yuǎn)程方法提供幫助的類,它也是最終用戶。我們將使用查找和調(diào)用遠(yuǎn)程方法的方法在該類中調(diào)用遠(yuǎn)程方法。
編程
我們將首先編寫遠(yuǎn)程對(duì)象,并將代碼保存為名字為AddServer.Java的文件:
import Java.rmi.*; public interface AddServer extends Remote { public int AddNumbers(int firstnumber,int secondnumber) throws RemoteException; } |
我們來(lái)看看上面的代碼。首先,為了使用其內(nèi)容,我們導(dǎo)入rmi包。然后,我們創(chuàng)建一個(gè)擴(kuò)展了Java.rmi中遠(yuǎn)程接口的接口。所有的遠(yuǎn)程對(duì)象
必須擴(kuò)展該遠(yuǎn)程接口,我們將該遠(yuǎn)程接口稱為AddServer。在該遠(yuǎn)程對(duì)象中,有一個(gè)名字為AddNumbers的方法,客戶端可以調(diào)用這一方法。我們
必須記住的是,所有的遠(yuǎn)程方法都需要啟動(dòng)RemoteException方法,有錯(cuò)誤發(fā)生時(shí)就會(huì)調(diào)用該方法。
下面我們開始編寫遠(yuǎn)程對(duì)象的實(shí)現(xiàn)。這是一個(gè)實(shí)現(xiàn)遠(yuǎn)程對(duì)象并包含有所有方法代碼的類,將下面的代碼保存為名字為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; } } |
首先,我們導(dǎo)入rmi包,然后創(chuàng)建一個(gè)擴(kuò)展UnicastRemoteObject和實(shí)現(xiàn)創(chuàng)建的遠(yuǎn)程對(duì)象的類;其次,我們可以為類創(chuàng)建一個(gè)缺省
的構(gòu)建器。我們還了解了AddNumbers方法的代碼,它啟動(dòng)RemoteException。這樣我們就覆蓋了創(chuàng)建的遠(yuǎn)程對(duì)象中的方法。
AddNumbers方法的代碼非常好理解,它接受2個(gè)整型參數(shù),然后相加并返回它們的和。
至此,我們已經(jīng)有了二個(gè)Java文件:遠(yuǎn)程對(duì)象和遠(yuǎn)程對(duì)象的實(shí)現(xiàn)。下面我們將使用Javac命令編譯這二個(gè)文件:
編譯遠(yuǎn)程對(duì)象:
C:\jdk\bin\Javac workingdir\AddServer.Java |
編譯遠(yuǎn)程對(duì)象實(shí)現(xiàn):
C:\jdk\bin\Javac workingdir\AddServerImpl.Java |
這樣,就會(huì)達(dá)到二個(gè)Java文件和二個(gè)類文件,下面我們將創(chuàng)建stub和skeleton。為了創(chuàng)建stub和skeleton文件,我們必須使用rmic編譯器編譯遠(yuǎn)程對(duì)象實(shí)現(xiàn)文件。
用Rmic編譯遠(yuǎn)程對(duì)象實(shí)現(xiàn)文件:
C:\jdk\bin\rmic workingdir\AddServerImpl.Java |
然后,我們就會(huì)發(fā)現(xiàn)多了2個(gè)新建的類文件,它們分別是AddServerImpl_Stub.class 和AddServerImpl_Skel.class 。
The Coding (Contd.)
我們已經(jīng)編譯了所有的源代碼,下面我們來(lái)創(chuàng)建客戶端和服務(wù)器端,將下面的代碼保存為名字為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); } } |
首先,我們導(dǎo)入Java.rmi包和Java.net包。另外,我們還使用throws從句捕獲任何異常。我們從對(duì)象中得出遠(yuǎn)程對(duì)象實(shí)現(xiàn),使用rebind方法將字符串a(chǎn)ddnumbers與該對(duì)象綁定。下面的例子顯示了綁定的含義:
從現(xiàn)在開始,無(wú)論何時(shí)客戶端要調(diào)用遠(yuǎn)程對(duì)象,使用字符串a(chǎn)ddnumbers就可以實(shí)現(xiàn)。rebind方法有二個(gè)參數(shù):第一個(gè)參數(shù)是字符串變量,第二個(gè)參數(shù)是遠(yuǎn)程對(duì)象實(shí)現(xiàn)類的對(duì)象。
下面我們來(lái)創(chuàng)建客戶端,將下面的代碼保存為名字為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); } } |
首先,我們導(dǎo)入Java.rmi包和Java.net包,并使用throws從句捕獲所有必要的異常。然后通過(guò)利用Naming類中的靜態(tài)lookup方法從遠(yuǎn)程對(duì)象中得到一個(gè)對(duì)象。(這也是我們無(wú)需從Naming類中得到一個(gè)對(duì)象并調(diào)用它。而只使用類名字的原因。)
lookup方法接受遠(yuǎn)程對(duì)象的完整的URL名字,該URL由完整的機(jī)器IP地址以及與對(duì)象綁定的字符串(也誻對(duì)象的綁定名)組成。在調(diào)用遠(yuǎn)程對(duì)象時(shí),
我們使用了RMI協(xié)議。lookup方法向我們返回一個(gè)對(duì)象,在能夠使用它前,我們必須將它的數(shù)據(jù)類型轉(zhuǎn)換為與遠(yuǎn)程對(duì)象的數(shù)據(jù)類型一致。
Since we have both our server and client source ready, let's compile them both: |
至此,我們已經(jīng)有了服務(wù)器端和客戶端的源代碼,下面我們來(lái)編譯這二個(gè)源文件:
編譯遠(yuǎn)程服務(wù)器:
C:\jdk\bin\Javac workingdir\RmiServer.Java |
編譯遠(yuǎn)程客戶端:
C:\jdk\bin\Javac workingdir\RmiClient.Java |
在對(duì)我們的代碼進(jìn)行測(cè)試前,還必須首先啟動(dòng)RMI Registry。RMI Registry存儲(chǔ)有所有綁定的數(shù)據(jù),沒(méi)有它,RMI就不能正常地運(yùn)行!
啟動(dòng)Rmi Registry服務(wù)器:
C:\jdk\bin\start rmiregistry |
我們會(huì)注意到,這時(shí)會(huì)出現(xiàn)一個(gè)空白的DOS提示符窗口,這表明Rmi Registry服務(wù)器在運(yùn)行,注意不要關(guān)閉該窗口。然后,我們首先在一個(gè)DOS提示符窗口中運(yùn)行Rmi服務(wù)器,然后在另一個(gè)DOS提示符窗口中運(yùn)行Rmi客戶端。
啟動(dòng)RMI服務(wù)器:
C:\jdk\bin\Java workingdir\RmiServer |
啟動(dòng)RMI客戶端:
C:\jdk\bin\Java workingdir\RmiClient |
posted on 2006-02-16 10:13 靜夜思 閱讀(270) 評(píng)論(0) 編輯 收藏 所屬分類: j2ee基礎(chǔ)