Java遠端方法呼叫
一、入門篇
Java RMI指的是遠端方法呼叫(Remote Method Invocation). 它是一種機制, 能夠讓不同作業系統之間程式實現方法呼叫.
比如: 一臺電腦上的Java程式可以通過RMI呼叫另一臺電腦上的方法(EJB底層就是使用RMI).
二、RMI和webservice
RMI是在TCP協議上傳遞可序列化的Java物件, 只能用在Java虛擬機器上, 客戶端和服務端必須都是Java.
webservice是在http協議上傳遞xml檔案, 它與語言和平臺無關, 可以在異構系統間傳遞.
對於不同語言間的通訊我們可以考慮用webservice或者公用物件請求代理體系COBRA來實現.
三、RMI的優點
RMI為分散式系統設計、程式設計帶來了遍歷. 只要按照RMI規則設計程式, 就不必過問網路細節, 如: TCP, Socket等.
任意兩臺計算機之間的通訊完全由RMI負責, 呼叫遠端計算機上的物件就像呼叫本地物件一樣方便.
四、例項篇
我們編寫這樣一個小程式: 客戶端傳遞兩個數字給伺服器端加法運算方法, 返回結果給客戶端.
1. 定義一個遠端介面類
/** * 定義一個遠端介面 * @author zhangjim */ public interface ISumService extends Remote { // 必須繼承Remote介面 // 需要遠端呼叫的方法必須丟擲RemoteException public int sum(int a, int b) throws RemoteException; }
遠端介面必須要繼承: java.rmi.Remote, 介面中的每一個方法必須丟擲遠端異常: java.rmi.RemoteException
為什麼要丟擲這個異常呢? 因為任何遠端方法呼叫實際上要進行許多低階網路操作, 而網路錯誤可能在呼叫過程中隨時發生.
因此, 所有RMI操作都應該放到try-catch塊中.
2. 定義一個實現遠端介面的類
UnicastRemoteObject: 讓客戶機與伺服器物件例項建立一對一的連線/** * 遠端介面的實現類 * @author zhangjim */ public class SumServiceImpl extends UnicastRemoteObject implements ISumService { // 必須從UnicastRemoteObject繼承 private static final long serialVersionUID = -3559316404683903070L; // 需要一個丟擲Remote異常的預設初始化方法 SumServiceImpl() throws RemoteException { } // 業務方法, 傳入兩個數字, 返回相加結果 public int sum(int a, int b) throws RemoteException { return a + b; } }
3. 建立伺服器, 用於啟動RMI服務並繫結遠端物件
public class Server {
public static void main(String[] args) {
try {
// 建立一個遠端物件
ISumService sumService = new SumServiceImpl();
// 建立RMI登錄檔, 啟動RMI服務, 並指定埠為8888(Java預設埠是1099)
// 這一步必不可少, 缺少登錄檔建立,則無法繫結物件到遠端登錄檔上
LocateRegistry.createRegistry(8888);
// 把遠端物件註冊到RMI註冊伺服器上,並命名為sum
// 繫結的URL標準格式為:rmi://host:port/name(其中協議名可以省略, 下面兩種寫法都是正確的)
Naming.bind("rmi://localhost:8888/sum", sumService);
// Naming.bind("//localhost:8888/sum", sumService);
System.out.println("遠端物件繫結成功!");
} catch (Exception e) {
throw new RuntimeException("出錯了...", e);
}
}
}
也可以在命令列通過命令 rmiregistry 啟動註冊服務, 而且要事先用RMIC在bin目錄編譯SumServiceImpl類生成一個佔位程式(stub類)為它所用
4. 建立客戶端程式, 對RMI進行呼叫
/**
* 客戶端測試,在客戶端呼叫遠端物件上的遠端方法,並返回結果
* @author zhangjim
*/
public class Client {
public static void main(String[] args) {
try {
// 在RMI服務登錄檔中查詢名稱為sum的物件
ISumService sumService = (ISumService) Naming.lookup("rmi://localhost:8888/sum");
// 呼叫相加方法
System.out.println("相加結果為: " + sumService.sum(1, 2));
} catch (Exception e) {
throw new RuntimeException("出錯了...", e);
}
}
}
五、RMI的文章