cmd

          RMI簡(jiǎn)要開(kāi)發(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ǔ)言開(kāi)發(fā)的CORBA不同的是,RMI是一種純Java解決方案。在RMI中,程序的所有部分都由Java編寫(xiě)。

            在看本篇文章時(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)看看必須編寫(xiě)哪些代碼:

            ·遠(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)程方法。
          編程

            我們將首先編寫(xiě)遠(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)用該方法。

            下面我們開(kāi)始編寫(xiě)遠(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)在開(kāi)始,無(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
            如果一切正常,我們應(yīng)該能夠得到15這個(gè)輸出。我們向AddNumbers方法輸入10和5二個(gè)數(shù)字,該方法將這二者加起來(lái),并將其和15返回 給我們。如果得到了15這個(gè)輸出,說(shuō)明我們已經(jīng)成功地執(zhí)行了一個(gè)遠(yuǎn)程方法。當(dāng)然,在這里,我們并沒(méi)有執(zhí)行真正意義上的遠(yuǎn)程方法,因?yàn)槲覀兊挠?jì)算機(jī)既是服務(wù) 器,又是客戶機(jī)。如果有計(jì)算機(jī)網(wǎng)絡(luò),我們就可以方便地進(jìn)行執(zhí)行遠(yuǎn)程方法的試驗(yàn)了。

          posted on 2006-02-16 10:13 靜夜思 閱讀(270) 評(píng)論(0)  編輯  收藏 所屬分類: j2ee基礎(chǔ)

          主站蜘蛛池模板: 旌德县| 九龙坡区| 姜堰市| 达尔| 阿拉善盟| 木兰县| 郸城县| 永清县| 眉山市| 昆山市| 类乌齐县| 磴口县| 青岛市| 彭山县| 岫岩| 嘉义县| 冀州市| 贡山| 邢台市| 抚顺县| 临汾市| 北宁市| 高台县| 疏附县| 锦屏县| 比如县| 乐业县| 广丰县| 徐汇区| 白沙| 怀集县| 江都市| 金平| 安乡县| 安徽省| 河西区| 惠州市| 石林| 资溪县| 大方县| 乌拉特后旗|