java遠程方法調用(RMI)

圖中顯示了一個分佈式的對象模型。在這個模型中,若是一個對象不只被本地訪問,並且還可以被遠程訪問,就稱爲遠程對象。java

若是一個對象只能被本地訪問,就被稱爲本地對象。web

圖中白色的橢圓表示本地對象,深色的橢圓表示遠程對象。安全

圖中實線表示常規的本地方法調用,虛線表示遠程方法調用。服務器

爲了保證各個對象之間的可靠地發送消息,該模型的實現一般使用TCP協議做爲網絡傳輸層的通訊協議。網絡

 

通常來講遠程對象分佈在服務器端,提供各類通用的訪問。多線程

對象模型的實現系統的功能:併發

1.把分佈在不一樣節點上的對象之間發送的消息轉換爲字節序列,這個過程稱爲編組。框架

2.經過套接字創建鏈接而且編組後發送。分佈式

3.處理網絡鏈接和傳輸時候的各類故障。性能

4.爲分佈在不一樣節點上的對象提供分佈式垃圾收集機制。

5.爲遠程方法調用提供安全檢查機制。

6.服務端運用多線程或者非阻塞通訊機制,確保遠程對象具備良好的併發性能,同時被多個客戶訪問。

7.建立於特定領域相關的各類本地對象和遠程對象。

 

一些現成的,成熟的分佈式對象模型的框架:

1.RMI(Remote Method Invoke,遠程方法調用):JDK提供一個完善的,簡單易用的遠程方法調用框架,它要求客戶端和服務端都是java程序。

2.CORBA(Common Object Request Broker Architecture,通用對象請求代理體系結構):分佈式對象模型的通用框架,容許不一樣的語言編寫

的對象可以彼此通訊。

3.SOAP(Simple Object Access Protocol,簡單對象訪問協議):容許異構的系統之間可以彼此通訊,以xml做爲通訊語言。一個系統可以訪問另外一個

系統對外公佈的web服務。

 

RMI框架封裝了全部底層通訊細節,而且解決了編組,分佈式垃圾回收,安全檢查和併發性等通用問題。開發人員只須要專一於開發與特定問題領域相關的

各類本地對象和遠程對象。

 

RMI對象爲遠程對象分佈生成了客戶端代理和服務端代理。位於客戶端的代理類叫作存根(Stub),位於服務端的代理類叫作骨架(Skeleton)。

客戶端調用遠程對象的一個方法的時候,其實是調用本地的存根對象的對應的方法。

存根對象與遠程對象實現了相同的接口。

存根對象採用平臺無關的編碼方式(java序列化機制)對方法的參數進行編組。

存根對象把如下信息發送給服務器:

1.被訪問的遠程對象的名字。

2.被調用的方法的名字。

3.編組後的參數的字節序列。

服務器接受到這些信息後,由骨架對象來進行處理:

1.反編組參數。

2.定位要訪問的對象。

3.調用遠程對象的相應方法。

4.獲取方法的結果或者異常信息,進行編組。

5.發送給客戶。

 

 建立遠程類

遠程類就是遠程對象所屬的類。RMI規範要求遠程類必須實現一個接口。此外,爲了使得遠程類的實例能變成爲遠程客戶提供服務的遠程對象,

能夠用兩種途徑中的一種把它導出爲遠程對象。

1.使遠程對象繼承java.rmi.server.UnicastRemoteObject類,而且遠程類的構造方法必須聲明拋出RemoteException。這是最經常使用的方式,

java語言的語言特徵是,在構造一個子類的實例時,java虛擬機會先自動調用UnicastRemoteObject父類的不帶參數的構造方法,它的定義如

下:

protected UnicastRemoteObject() throws RemoteException

{

  this(0);

}

protected UnicastRemoteObject(int port)throws RemoteException

{

  this.port = port;

  exportObject((Remote)this,port);

}

由此,UnicastRemoteObject類的構造方法會調用自身的靜態方法exportObject(Remote obj,int port)。該方法負責把參數obj指定的對象導出爲

遠程對象,使得它具備相應的存根,而且使得它可以監聽遠程客戶的請求。參數port指定監聽的端口,若是取值爲0,表示任意一個匿名端口。

2.若是一個遠程對象已經繼承了一個類,沒法再繼承UnicastRemoteObject類,那麼能夠再構造方法中調用UnicastRemoteObject類的靜態

exportObject()方法。一樣,遠程類的構造方法必須聲明拋出RemoteException異常。

 

遠程類的注意事項:

1.遠程類的構造方法必須聲明拋出RemoteException,若是導出失敗,就會拋出這種異常。

2.全部遠程方法必須拋出RemoteException。

3.在遠程類中能夠定義一些本地方法,即沒有在遠程接口中聲明的方法。這些方法無需拋出RemoteException.它們只能被本地調用,不容許被

遠程調用。

4.UnicastRemoteObject類覆蓋了Object類的hashCode(),equals()和clone()方法。若是一個遠程對象繼承了UnicastRemoteObject類,就能夠

繼承它的這些方法。

 

查找遠程對象

1.jdk1.3及之前版本,jdk的bin目錄下有一個rmiregistry.exe程序。服務器向rmiregistry註冊表註冊遠程對象。

2.jdk1.3之後,rmi的命名服務API被整合到JNDI(java Naming and Directory Interface,java名字與目錄服務)中。

在JNDI中,javax.naming.Context接口聲明瞭註冊,查找以及銷燬對象的方法。

public void bind(String name,Object obj)

註冊對象,把對象與一個名稱綁定。若是該名字已經與其餘對象綁定,就會拋出NameAlreayBoundException。

public void rebind(String name,Object obj)

若是綁定了,就覆蓋綁定。

lookup(String name)

查找對象

unbind(String name)

註銷對象

 

段1:

HelloService helloService = new HelloServiceImpl("service1");

Context namingContext = new InitialContext();

namingContext.rebind("rmi:HelloService1",helloService);

段分析:

默認狀況下,InitialContext的rebind()方法會把HelloServiceImpl對象註冊到本地主機上的監聽1099端口的rmiregistry註冊表中,

而且賦予特定的名字HelloService1,該HelloServiceImpl的完整名字爲:

rmi://localhost:1099/HelloService1

能夠把段1改寫爲:

段2:

namingContext.rebind("rmi://localhost:1099/HelloService1",helloService);

或者

段3:

namingContext.rebind("rmi://localhost/HelloService1",helloService);

客戶端獲取遠程對象

段4:

Context namingContext = new InitialContext();

HelloService service1 == (HelloService)namingContext.lookup("rmi://localhost/HelloService1");

客戶端必須提供完整名字:

rmi://服務端的名字:端口號/對象的註冊名字

相關文章
相關標籤/搜索