分布式/RMI 2009-06-08 21:39 創(chuàng)建一個(gè)rmi應(yīng)用主要包括以下步驟: 1 創(chuàng)建遠(yuǎn)程接口:繼承java.rmi.Remote接口 2 創(chuàng)建遠(yuǎn)程類:實(shí)現(xiàn)遠(yuǎn)程接口 3 創(chuàng)建服務(wù)器程序:負(fù)責(zé)向rmiregistry注冊(cè)表中注冊(cè)遠(yuǎn)程對(duì)象 4 創(chuàng)建客戶程序:負(fù)責(zé)定位遠(yuǎn)程對(duì)象,并且調(diào)用遠(yuǎn)程對(duì)象的方法
(一)創(chuàng)建遠(yuǎn)程接口 (1)直接或間接繼承java.rmi.Remote接口 (2)接口中所有方法聲明拋出java.rmi.RemoteExeption 遠(yuǎn)程方法調(diào)用依賴于網(wǎng)絡(luò)通信,一旦服務(wù)器或客戶端有一方突然斷開連接,或者網(wǎng)絡(luò)出現(xiàn)故障,通信就會(huì)失敗。RMI框架會(huì)把遇到的網(wǎng)絡(luò)故障通信失敗轉(zhuǎn)化為RemoteException,客戶端可以捕獲這種異常并進(jìn)行處理 package hello; import java.rmi.Remote; public interface HelloService extends Remote{ String echo(String msg)throws RemoteException; 創(chuàng)建遠(yuǎn)程接口時(shí),還可以采用以下方式: public interface A { String echo(String msg)throws IOException; public interface B extends A,Remote{} 以上接口A不是遠(yuǎn)程接口,而子接口B是遠(yuǎn)程接口。由于A中聲明的方法拋出的異常都是RemoteException的父類,因此這些方法在接口B中都可以作為遠(yuǎn)程方法。這種創(chuàng)建接口的方法有以下優(yōu)點(diǎn): 對(duì)本來(lái)不是為RMI而設(shè)計(jì)的接口A,無(wú)須對(duì)他作任何變動(dòng),只需創(chuàng)建一個(gè)繼承Remote接口的子接口B,就能增加對(duì)RMI的支持 接口A不依賴于RMI,能隱藏系統(tǒng)中RMI的細(xì)節(jié),使系統(tǒng)可以在保持接口A不變的情況下靈活的改變實(shí)現(xiàn)細(xì)節(jié)。
(二) 創(chuàng)建遠(yuǎn)程類 package hello; import java.rmi.RemoteException; // 在此遠(yuǎn)程類繼承了一個(gè)UnicastRemoteObject 類 public class HelloServiceImpl extends UnicastRemoteObject implements HelloService { private String name; public HelloServiceImpl(String name) throws RemoteException { } public String echo(String msg) throws RemoteException { System.out.println(name + ":調(diào)用echo()方法"); public Date getTime() throws RemoteException { System.out.println(name + ":調(diào)用getTime()方法"); } 遠(yuǎn)程類就是實(shí)際要調(diào)用的那些業(yè)務(wù)類等,用來(lái)創(chuàng)建遠(yuǎn)程對(duì)象。 所有的遠(yuǎn)程對(duì)象,都必須通過(guò)調(diào)用類java.rmi.server.UnicastRemoteObject的方法exportObjext(Remote r, int port) 導(dǎo)出為遠(yuǎn)程對(duì)象(能夠生成對(duì)應(yīng)的stub和骨架對(duì)象) 在上面的例子中通過(guò)繼承UnicastRemoteObject,在構(gòu)造函數(shù)中會(huì)調(diào)用UnicastRemoteObject的構(gòu)造子執(zhí)行exportObjext(this,0),若要指定其他端口,調(diào)用super(int port) public HelloServiceImpl(String name) throws RemoteException { super(111); } 也可以 public HelloServiceImpl(String name) throws RemoteException { UnicastRemoteObject.exportObjext(this,0); } 以上的構(gòu)造函數(shù)要拋出RemoteException
(三 創(chuàng)建服務(wù)器程序) RMI采用一種命名服務(wù)機(jī)制來(lái)使客戶端程序可以找到服務(wù)器上的一個(gè)遠(yuǎn)程對(duì)象。在jdk安裝目錄的bin目錄下有一個(gè)rmiregistry.exe程序,它是提供命名服務(wù)的注冊(cè)表程序。 服務(wù)器的一大任務(wù)就是向注冊(cè)表中注冊(cè)遠(yuǎn)程對(duì)象。 從JDK1.3以上版本開始,RMI命名服務(wù)的API被整合到JNDI中,在JNDI中,javax.naming.Context接口聲明了注冊(cè),查找以及注銷對(duì)象的方法: bind(String name , Object obj):注冊(cè)對(duì)象,把一個(gè)對(duì)象與一個(gè)名字綁定。如果該名字已經(jīng)和其他對(duì)象綁定,就會(huì)拋出NameAlreadyBoundException rebind(String name, Object obj):注冊(cè)對(duì)象,把對(duì)象與一個(gè)名字綁定。如果該名字已經(jīng)和其他對(duì)象綁定,不會(huì)拋出NameAlreadyBoundException,而是覆蓋 lookup(String name):查找對(duì)象,返回參數(shù)name指定的名字所綁定的對(duì)象 unbind(String name):注銷對(duì)象,取消綁定。 package hello; import java.rmi.Naming; import javax.naming.Context; public class SimpleServer { public static void main(String[] args) { // 也可以直接使用RMI的API進(jìn)行綁定 在將遠(yuǎn)程對(duì)象綁定時(shí)的名稱并沒(méi)有寫全,都省略了一部分內(nèi)容: 對(duì)JNDI API注冊(cè),名稱必須以rmi:開頭,默認(rèn)情況下IntialContext的rebind方法會(huì)把HelloServieceImpl對(duì)象注冊(cè)到本地主機(jī)上的監(jiān)聽1099端口的rmiregistry注冊(cè)表進(jìn)程中(RMI整合到JNDI中了) 對(duì)直接應(yīng)用RMI API注冊(cè)無(wú)此限制,不用一rmi:開頭就可以實(shí)現(xiàn)以上默認(rèn) 而該HelloServiceImpl對(duì)象的全名為:rmi://localhost:1099/HelloService1 因此給出全名稱時(shí): namingContext.rebind("rmi://localhost:1099/HelloService1", service1); 或 Naming.rebind("rmi://localhost:1099/HelloService1", service1); 而客戶端在通過(guò)名稱訪問(wèn)遠(yuǎn)程對(duì)象時(shí),必須向lookUp方法提供遠(yuǎn)程對(duì)象的完整名字: rmi://服務(wù)器名字:端口號(hào)/對(duì)象注冊(cè)的名字 服務(wù)器名字指的是rmiregistry注冊(cè)表程序所在的主機(jī)名,端口號(hào)是指rmiregistry監(jiān)聽的端口號(hào)。默認(rèn)情況下,rmiregistry監(jiān)聽1099端口,在這種情況下以上url可省略端口號(hào)。 |
聯(lián)系客服