RMI(遠程方法調用)實現簡單的查單詞功能

1. RMI概念

        RMI(Remote Method Invocation),遠程方法調用,是Java的一組擁護開發分佈式應用程序的API。RMI使用Java語言接口定義了遠程對象,它集合了Java序列化和Java遠程方法協議(Java Remote Method Protocol)。簡單地說,這樣使原先的程序在同一操作系統的方法調用,變成了不同操作系統之間程序的方法調用,由於J2EE是分佈式程序平臺,它以RMI機制實現程序組件在不同操作系統之間的通信。比如,一個EJB可以通過RMI調用Web上另一臺機器上的EJB遠程方法。

2. 工作原理

        在RMI中,調用遠程對象的對象被稱爲客戶機對象(Client   Object)而遠程對象被稱爲服務器對象(Server   Object),同時引入了兩種特殊類型對象,存根(stub)和框架(Skelton)。存根實際上是遠程對象的客戶端代理,它和遠程對象具有相同的接口或方法列表,當客戶端調用遠程對象時,實際上是由相應的存根對象代理完成。在服務器端,框架對象處理“遠方”的所有細節,完全可以像編寫本地對象一樣來編寫遠程對象。框架將遠程對象從RMI基礎結構分離開來。也就是說,客戶端獲得的只是代理對象,並不是服務器上的類型,只不過它實現了服務器上類型的全部功能。

3. 實例

實現簡單的查單詞功能,一臺應用服務器以RMI的方式向客戶端提供英譯漢詞典的服務。

創建一個簡單的Java分佈式遠程方法調用程序可以按以下幾個步驟操作:

1)定義遠程接口

/**
 * 功能說明:定義一個遠程接口,必須繼承Remote接口,其中需要遠程調用的方法必須拋出RemoteException異常 
 * 作者: gangwazi
 * 創建時間:2012-6-27
 */
public interface WordTranslate extends Remote {
	/**
	 * @param str 需要被翻譯的單詞
	 * @return 英漢互譯後的內容,如果詞典中不包含此單詞返回null
	 */
	public String translate(String str) throws RemoteException;
}

2)實現遠程接口

/**
 * 功能說明:遠程接口的實現
 * 作者: gangwazi
 * 創建時間:2012-6-27
 */
public class WordTranslateImpl extends UnicastRemoteObject implements WordTranslate {

	private static final long serialVersionUID = 1L;
	public Map<String, String> wordMap = new HashMap<String, String>();

	// 因爲UnicastRemoteObject的構造方法拋出了RemoteException異常,因此這裏默認的構造方法必須寫,必須聲明拋出RemoteException異常 
	public WordTranslateImpl() throws RemoteException {
		super();
		wordMap.put("China", "n. 中國");
		wordMap.put("Japan", "n. 日本");
		wordMap.put("German", "德國");
		wordMap.put("list", "n. 列表; v. 列出");
		wordMap.put("egg", "n. 雞蛋");
		wordMap.put("map", "n. 地圖");
		wordMap.put("translate", "v. 翻譯");
		wordMap.put("banana", "n. 香蕉");
		wordMap.put("apple", "n. 蘋果");
		wordMap.put("orange", "n. 橘子");
		wordMap.put("milk", "n. 牛奶");
		wordMap.put("water", "n. 水");
		wordMap.put("drink", "v. 喝,飲");
	}

	@Override
	public String translate(String str) throws RemoteException {
		if (wordMap.containsKey(str)) {
			return wordMap.get(str);
		} else {
			return null;
		}
	}

}
由於只是簡單的示例,故詞典使用map來存儲,當然也可以構造專門的詞典文件或者從數據庫中查詢。

3)編寫服務器類

/**
 * 功能說明:創建RMI註冊表,啓動RMI服務,並將遠程對象註冊到RMI註冊表中。 
 * 作者: gangwazi
 * 創建時間:2012-6-27
 */
public class WordTranslateServer {

	public static void main(String[] args) {
		try {
			// 創建一個遠程對象
			WordTranslate rTranslate = new WordTranslateImpl();
			// 本地主機上的遠程對象註冊表Registry的實例,並指定端口爲5555,這一步必不可少(Java默認端口是1099),
			// 必不可缺的一步,缺少註冊表創建,則無法綁定對象到遠程註冊表上 
            LocateRegistry.createRegistry(5555);
            // 把遠程對象註冊到RMI註冊服務器上,並命名爲RTranslate
            // 綁定的URL標準格式爲:rmi://host:port/name(其中協議名可以省略)
            Naming.bind("rmi://localhost:5555/RTranslate", rTranslate);
            System.out.println(">>>>>INFO: 遠程WorldTranslate對象綁定成功!");
		} catch (RemoteException e) {
			System.out.println("創建遠程對象發生異常!");
			e.printStackTrace();
		} catch (MalformedURLException e) {
			System.out.println("發生URL畸形異常!");
			e.printStackTrace();
		} catch (AlreadyBoundException e) {
			System.out.println("發生重複綁定對象異常!");
			e.printStackTrace();
		}
	}
}

4)編寫客戶端類

/**
 * 功能說明:客戶端測試,在客戶端調用遠程對象上的遠程方法,並返回結果。
 * 作者: gangwazi
 * 創建時間:2012-6-27
 */
public class WorldTranslateClient {

	public static void main(String[] args) {
		try {
			// 在RMI服務註冊表中查找名稱爲RTranslate的對象,並調用其上的方法 
			WordTranslate rTranslate = (WordTranslate) Naming.lookup("rmi://202.117.10.64:5555/RTranslate");
			System.out.print("查詢單詞 China----------->");
			System.out.println(rTranslate.translate("China"));
			System.out.print("查詢單詞 list----------->");
			System.out.println(rTranslate.translate("list"));
			System.out.print("查詢單詞 present----------->");
			System.out.println(rTranslate.translate("present"));
			System.out.print("查詢單詞 banana----------->");
			System.out.println(rTranslate.translate("banana"));
			System.out.print("查詢單詞 util----------->");
			System.out.println(rTranslate.translate("util"));
			System.out.print("查詢單詞 drink----------->");
			System.out.println(rTranslate.translate("drink"));
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

4. 運行結果

服務器端和客戶端分別運行在兩臺機子上

服務器端運行結果


客戶端運行結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章