RMI實用教程
Java Remote Method Invocation ( RMI -- Java遠程方法調用)允許您使用Java編寫分布式對象。本文將介紹RMI的優點以及如何將其連接到現有的和原有的系統中,以及與用Java 編寫的組件的連接,同時給出了一個詳細的例子,可以給初學者提供一個學習范本?! ?
一、RMI(遠程方法調用)的組成
一個正常工作的RMI系統由下面幾個部分組成:
1、遠程服務的接口定義
2、遠程服務接口的具體實現
3、樁(Stub)和框架(Skeleton)文件
4、一個運行遠程服務的服務器
5、一個RMI命名服務,它允許客戶端去發現這個遠程服務
6、類文件的提供者(一個HTTP或者FTP服務器)
7、一個需要這個遠程服務的客戶端程序
二、RMI(遠程方法調用)的工作原理
RMI系統結構,在客戶端和服務器端都有幾層結構。
--------- ----------
| 客戶 | | 服務器|
---------- ----------
| |
------------- ----------
| 占位程序 | | 骨干網 |
-------------- -----------
| |
------------------------------------
| 遠 程 引 用 層 |
------------------------------------
| |
------------------------------------
| 傳 輸 層 |
------------------------------------
方法調用從客戶對象經占位程序(Stub)、遠程引用層(Remote Reference Layer)和傳輸層(Transport Layer)向下,傳遞給主機,然后再次經傳 輸層,向上穿過遠程調用層和骨干網(Skeleton),到達服務器對象。 占位程序扮演著遠程服務器對象的代理的角色,使該對象可被客戶激活。 遠程引用層處理語義、管理單一或多重對象的通信,決定調用是應發往一個服務器還是多個。傳輸層管理實際的連接,并且追追蹤可以接受方法調用的遠程對象。服務器端的骨干網完成對服務器對象實際的方法調用,并獲取返回值。返回值向下經遠程引用層、服務器端的傳輸層傳遞回客戶端,再向上經傳輸層和遠程調用層返回。最后,占位程序獲得返回值。
要完成以上步驟需要有以下幾個步驟:
1、生成一個遠程接口
2、實現遠程對象(服務器端程序)
3、編寫服務器程序 、注冊遠程對象、啟動遠程對象
4、編寫客戶程序
在JDK1.5之后,用java提供的API將會更加的簡單,可以參照下面的例子;
三、例子
1、遠程接口
接口名:com.liuxiang.rmi.download.IRMI
該接口定義了一個方法,用于提供遠程服務;
/**
*
*/
package com.liuxiang.rmi.download;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* 遠程對象接口
* @author liuxiang
* 2007-8-30 下午09:39:15
*
*/
public interface IRMI extends Remote{
public Object invoke(ITask task) throws RemoteException;
}
2、實現遠程對象(服務器端程序)
類名:com.liuxiang.rmi.download.IRMIImpl
實現了遠程接口定義的方法;該實現遠程對象中,調用了傳入參數的task.doWork()方法,同時執行一個本地調用,調用一個播放Mp3的代碼段ProcessCaller.callMp3();
/**
*
*/
package com.liuxiang.rmi.download;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import com.liuxiang.callwindow.ProcessCaller;
/**
* 遠程對象的實現
* @author liuxiang
* 2007-8-30 下午09:41:32
*
*/
public class IRMIImpl extends UnicastRemoteObject implements IRMI {
protected IRMIImpl() throws RemoteException {
super();
}
/**
*
*/
private static final long serialVersionUID = 6131922116577454476L;
/* (non-Javadoc)
* @see com.liuxiang.rmi.download.IRMI#invoke(com.liuxiang.rmi.download.ITask)
*/
public Object invoke(ITask task) throws RemoteException {
System.out.println("注意:這是一個遠程調用");
Object obj = task.doWork();
System.out.println("調用ITask.doWork()方法的返回值:"+obj.toString());
//客戶端調用,可以在服務器端播放需要的音樂
ProcessCaller.callMp3();
return obj;
}
}
3、播放Mp3代碼段的源代碼如下:
/**
*
*/
package com.liuxiang.callwindow;
/**
* 在java中調用windows程序
* @author liuxiang 2007-8-30 下午10:26:20
*
*/
public class ProcessCaller {
/**
* 調用Windows程序
* 利用Windows Media Player播放mp3音樂
*/
public static void callMp3() {
Runtime ru = Runtime.getRuntime();
try {
// 調用播放器文件播放指定MP3
Process p1 = ru
.exec("C:\Program Files\Windows Media Player\wmplayer F:/music/lx/劉若英-后來.mp3");
} catch (Exception e) {
}
}
/**
* @param args
*/
public static void main(String[] args) {
callMp3();
}
}
4、任務接口
該接口定義了遠程方法需要傳遞的參數
/**
*
*/
package com.liuxiang.rmi.download;
import java.io.Serializable;
/**
* 任務接口
* @author liuxiang
* 2007-8-30 下午09:35:53
*
*/
public interface ITask extends Serializable{
public Object doWork();
}
5、任務接口實現
該實現定義了遠程方法需要傳遞的參數
package com.liuxiang.rmi.download;
/**
* 任務實現類
* @author liuxiang
* 2007-8-31 上午09:08:57
*
*/
public class TaskImpl implements ITask{
public Object doWork() {
System.out.println("當前程序處于遠程調用中");
return "動態上載對象的返回值";
}
}
6、編寫服務器程序 、注冊遠程對象、啟動遠程對象
代碼:遠程對象的注冊類 該類應該在服務器端執行 執行之后, 該機器將變為RMI服務器 客戶端可以通過正確的url來訪問;服務器上的遠程對象;執行對外報露的方法
/**
*
*/
package com.liuxiang.rmi.download;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
/**
* 遠程對象的注冊類 該類應該在服務器端執行 執行之后,
* 該機器將變為RMI服務器 客戶端可以通過正確的url來訪問
* 服務器上的遠程對象;執行對外報露的方法
*
* @author liuxiang 2007-8-30 下午09:44:54
*
*/
public class RMIServer {
/**
* 如果沒有創建一個Registry,Naming是不會幫助你創建的。 還是自己手工創建的比較的好
*
* 盡量用下面的自己封裝的bind方法來注冊遠程對象
*
* @throws Exception
*/
public static void registRemoteObject() throws Exception {
IRMIImpl impl = new IRMIImpl();
Naming.rebind("rmi://219.233.8.97:1111/mytask", impl);
System.out.println("bound success!");
}
/**
* 創建一個Registry對象
*
* @return 返回一個Registry對象
*/
private static Registry createRegistry() {
Registry registry = null;
int port = 1111;
try {
registry = LocateRegistry.getRegistry(port);
registry.list();
System.out.println("Register the exist server!");
} catch (final Exception e) {
try {
registry = LocateRegistry.createRegistry(port);
System.out.println("Register the exist server!port=" + port);
} catch (final Exception ee) {
ee.printStackTrace();
}
}
return registry;
}
/**
* 將對象注冊到rmi服務器上
*/
public static void bind() {
Registry registry = null;
registry = createRegistry();
try {
IRMIImpl impl = new IRMIImpl();
registry.rebind("mytask", impl);
System.out.println("mytask server start!");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
try {
bind();
} catch (Exception e) {
e.printStackTrace();
}
}
}
運行該服務端代碼后,將會注冊一個遠程服務對象,通過恰當的URL可以訪問遠程對象中的方法;運行后的結果如下:
Register the exist server!port=1111
mytask server start!
7、編寫客戶程序
代碼首先獲取一個遠程對象,然后如同本地調用一樣,調用遠程對象中的方法。
/**
*
*/
package com.liuxiang.rmi.download;
import java.rmi.Naming;
/**
* @author liuxiang
* 2007-8-30 下午09:47:41
*
*/
public class RMIClient {
/**
* 調用遠程對象中的方法
* @throws Exception
*/
public static void getRemoteObject() throws Exception{
IRMI obj = (IRMI)Naming.lookup("rmi://localhost:1111/mytask"); //得到遠程發布的服務
TaskImpl task = new TaskImpl();
Object result = obj.invoke(task); //調用遠程服務的方法
System.out.println(result.toString());
}
/**
* @param args
*/
public static void main(String[] args) {
try {
getRemoteObject();
} catch (Exception e) {
e.printStackTrace();
}
}
}
最后,運行客戶端代碼,可以看到控制臺分別輸出了如下的內容:
Server端輸出了更多的內容,如下:
Register the exist server!port=1111
mytask server start!
注意:這是一個遠程調用
當前程序處于遠程調用中
調用ITask.doWork()方法的返回值:動態上載對象的返回值
同時可以看到,會調用了Windows的Mediaplay播放本地磁盤的Mp3歌曲;
Client端輸入了如下內容:
動態上載對象的返回值
四、RMI介紹
RMI(Remote Method Invocation,遠程方法調用)是用Java在JDK1.1中實現的,它大大增強了Java開發分布式應用的能力。Java作為一種風靡一時的網絡開發語言,其巨大的威力就體現在它強大的開發分布式網絡應用的能力上,而RMI就是開發百分之百純Java的網絡分布式應用系統的核心解決方案之一。其實它可以被看作是RPC的Java版本。但是傳統RPC并不能很好地應用于分布式對象系統。而Java RMI 則支持存儲于不同地址空間的程序級對象之間彼此進行通信,實現遠程對象之間的無縫遠程調用。
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為采用Java對象的分布式計算提供了簡單而直接的途徑。這些對象可以是新的Java對象,也可以是圍繞現有API的簡單的Java包裝程序。Java體現了“編寫一次就能在任何地方運行的模式。而RMI可將Java模式進行擴展,使之可在任何地方運行”。
因為RMI是以Java為核心的,所以,它將Java的安全性和可移植性等強大功能帶給了分布式計算。您可將代理和梢?務邏輯等屬性移動到網絡中最合適的地方。如果您要擴展Java在系統中的使用,RMI將使您充分利用其強大功能。
RMI可利用標準Java本機方法接口JNI與現有的和原有的系統相連接。RMI還可利用標準JDBC包與現有的關系數據庫連接。RMI/JNI和RMI/JDBC相結合,可幫助您利用RMI與目前使用非Java語言的現有服務器進行通信,而且在您需要時可擴展Java在這些服務器上的使用。RMI可幫助您在擴展使用時充分利用Java的強大功能。