java RMI學習筆記

RMI(Remote Method)

Invocation):遠程方法調用,即在RPC的基礎上有向前邁進了一步,提供分布式對象間的通訊。允許運行在一個java虛擬機的對象調用運行在另一個java虛擬機上對象的方法。這兩個虛擬機可以是運行在相同計算機上的不同進程中,也可以是運行在網絡上的不同計算機中。

Java RMI 威力強大

Java RMI在JDK1.1中實現的,其威力就體現在它強大的開發分布式網絡應用的能力上,是純Java的網絡分布式應用系統的核心解決方案之一。其實它可以被看作是RPC的Java版本。但是傳統RPC并不能很好地應用于分布式對象系統。而Java RMI則支持存儲于不同地址空間的程序級對象之間彼此進行通信,實現遠程對象之間的無縫遠程調用。

Java遠程消息交換協議JRMP

RMI目前使用Java遠程消息交換協議JRMP(Java Remote Messaging Protocol)進行通信。由于JRMP是專為Java對象制定的,Java RMI具有Java的"Write Once,Run Anywhere"的優點,是分布式應用系統的百分之百純Java解決方案。用Java RMI開發的應用系統可以部署在任何支持JRE(Java Run Environment Java,運行環境)的平臺上。但由于JRMP是專為Java對象制定的,因此,RMI對于用非Java語言開發的應用系統的支持不足。不能與用非Java語言書寫的對象進行通信。

使用RMI優點

RMI大大增強了java開發分布式應用的能力,例如可以將計算方法復雜的程序放在其他的服務器上,主服務器只需要去調用,而真正的運算是在其他服務器上進行,最后將運算結果返回給主服務器,這樣就減輕了主服務器的負擔,提高了效率(但是也有其他的開銷)。

RMI網絡模型

在客戶端為遠程對象安裝一個代理。代理是位于客戶端虛擬機中的一個對象,它對于客戶端程序來說,就像是要訪問的遠程對象一樣。客戶端調用此代理時,只需進行常規的方法調用。而客戶端代理則負責使用網絡協議與服務器進行聯系。

網絡模型

圖片.png

RMI的工作原理

一、術語介紹

1、存根:當客戶端要調用遠程對象的一個方法時,實際上調用的是代理對象上的一個普通方法,我們稱此代理對象為存根(stub)。存根位于客戶端機器上,而非服務器上。

2、參數編組:存根會將遠程方法所需的參數打包成一組字節,對參數編碼的過程就稱為參數編組。參數編組的目的是將參數轉換成適合在虛擬機之間進行傳遞的格式,在RMI協議中,對象是使用序列化機制進行編碼的。

RMI遠程調用步驟:

1,客戶對象調用客戶端輔助對象上的方法

2,客戶端輔助對象打包調用信息(變量,方法名),通過網絡發送給服務端輔助對象

3,服務端輔助對象將客戶端輔助對象發送來的信息解包,找出真正被調用的方法以及該方法所在對象

4,調用真正服務對象上的真正方法,并將結果返回給服務端輔助對象

5,服務端輔助對象將結果打包,發送給客戶端輔助對象

6,客戶端輔助對象將返回值解包,返回給客戶對象

7,客戶對象獲得返回值

對于客戶對象來說,步驟2-6是完全透明的

編碼實現java RMI hello world的例子

定義一個接口


/**

* Created by junyi.pc on 2017/1/23.

*/

importjava.rmi.RemoteException;

importjava.rmi.*;

public interface IHello extends Remote {

/**

* 簡單的返回“Hello World!"字樣

*

*@return返回“Hello World!"字樣

*@throwsjava.rmi.RemoteException

*/

public default String helloWorld()throwsRemote Exception {

return null;

}

/**

* 一個簡單的業務方法,根據傳入的人名返回相應的問候語

*@paramsomeBodyName人名

*@return返回相應的問候語

*@throwsjava.rmi.RemoteException

*/

publicString sayHelloToSomeBody(String someBodyName)throwsRemoteException;

}

接口實現


/**

* Created by junyi.pc on 2017/1/23.

*/

importjava.rmi.RemoteException;

importjava.rmi.*;

importjava.rmi.server.UnicastRemoteObject;

public class HelloImpl extends UnicastRemoteObject implements IHello {

/**

* 因為UnicastRemoteObject的構造方法拋出了RemoteException異常,因此這里默認的構造方法必須寫,必須聲明拋出RemoteException異常

*

*@throwsRemoteException

*/

public HelloImpl()throws RemoteException {

}

/**

* 簡單的返回“Hello World!"字樣

*

*@return返回“Hello World!"字樣

*@throwsjava.rmi.RemoteException

*/

publicString helloWorld()throwsRemoteException {

return"Hello World!";

}

/**

* 一個簡單的業務方法,根據傳入的人名返回相應的問候語

*

*@paramsomeBodyName人名

*@return返回相應的問候語

*@throwsjava.rmi.RemoteException

*/

publicString sayHelloToSomeBody(String someBodyName)throwsRemoteException {

return"你好,"+ someBodyName +"!";

}

}

server實現


/**

* Created by junyi.pc on 2017/1/23.

*/

importjava.net.MalformedURLException;

importjava.rmi.AlreadyBoundException;

importjava.rmi.Naming;

importjava.rmi.RemoteException;

importjava.rmi.registry.LocateRegistry;

public classHelloServer {

public static voidmain(String args[]) {

try{

//創建一個遠程對象

IHello rhello =new HelloImpl();

//本地主機上的遠程對象注冊表Registry的實例,并指定端口為8888,這一步必不可少(Java默認端口是1099),必不可缺的一步,缺少注冊表創建,則無法綁定對象到遠程注冊表上

LocateRegistry.createRegistry(8888);

//把遠程對象注冊到RMI注冊服務器上,并命名為RHello

//綁定的URL標準格式為:rmi://host:port/name(其中協議名可以省略,下面兩種寫法都是正確的)

Naming.bind("rmi://localhost:8888/RHello",rhello);

//            Naming.bind("http://localhost:8888/RHello",rhello);

System.out.println(">>>>>INFO:遠程IHello對象綁定成功!");

}catch(RemoteException e) {

System.out.println("創建遠程對象發生異常!");

e.printStackTrace();

}catch(AlreadyBoundException e) {

System.out.println("發生重復綁定對象異常!");

e.printStackTrace();

}catch(MalformedURLException e) {

System.out.println("發生URL畸形異常!");

e.printStackTrace();

}

}

}

客戶端測試程序


/**

* Created by junyi.pc on 2017/1/23.

*/

importjava.net.MalformedURLException;

importjava.rmi.Naming;

importjava.rmi.NotBoundException;

importjava.rmi.RemoteException;

/**

* Created by junyi.pc on 2017/1/23.

*/

public class client {

public static voidmain(String args[]){

try{

//在RMI服務注冊表中查找名稱為RHello的對象,并調用其上的方法

IHello rhello =(IHello) Naming.lookup("rmi://localhost:8888/RHello");

System.out.println(rhello.helloWorld());

System.out.println(rhello.sayHelloToSomeBody("張俊怡"));

}catch(NotBoundException e) {

}catch(MalformedURLException e) {

e.printStackTrace();

e.printStackTrace();

}catch(RemoteException e) {

e.printStackTrace();

}

}

}

運行結果

A1VY8T$)~D`)1WQR`$3B~R7.png

![}J24D(99_)8VE%PEJ68PMN.png

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,973評論 19 139
  • Java是一個支持并發、基于類和面向對象的計算機編程語言。下面列出了面向對象軟件開發的優點: 代碼開發模塊化,更易...
    安安靜靜寫代碼閱讀 1,103評論 0 8
  • Java 面試題 整理自牛客網 什么是Java虛擬機?為什么Java被稱作是“平臺無關的編程語言”? Java虛擬...
    GuaKin_Huang閱讀 10,684評論 19 265
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,767評論 18 399
  • 回家 作者︳媚影 從沒有一個地方讓我如此魂牽夢繞 也從沒有一些人讓我們時常夢起 那熱氣騰騰的餃子 一大桌滿滿的菜 ...
    媚影心語閱讀 222評論 3 3