圖中顯示了一個分佈式的對象模型。在這個模型中,若是一個對象不只被本地訪問,並且還可以被遠程訪問,就稱爲遠程對象。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://服務端的名字:端口號/對象的註冊名字