一、RMI的工作原理
RMI能讓一個Java程序去調用網絡中另一臺計算機的Java對象的方法,那麼調用的效果就像是在本機上調用一樣。
二、RMI遠程地調用的步驟
- 調用者用通常方式調用對應java的一個遠程對象的方法
- 客戶stub的功能是把相關的參數組裝成一個消息包或一組消息包。運行此方法的那個“站點”的地址和對象及方法的“標識符”、調用方法的參數都應包含在這條消息中。
- 將這條消息發送給對應的RMI運行時系統,該程序在轉至指定的站點。
- 在接受此消息時,遠程RMI運行時系統引用與被調用者對應的服務stub,並讓它來處理這條消息。
- 服務器stub來反序列化有關參數,並用本地方法調用方式調用所需方法,然後把調用結果序列化,向調用者返回結果。
- 調用方RMI運行時系統棘手返回結果。調用者stub反序列化參數,然後,返回結果到調用方法。
三、RMI應用的基本開發步驟
案例:開發一個遠程調用方法 rmb2Dollar(double rmb),它把客戶(調用者)提供的人民幣(rmb)數值傳送個服務器,服務器按照一定的美元匯率將其返回。
1、定義遠程服務接口類(Converter.java)
遠程服務接口類必須繼承java.rmi.Remote接口,並且在業務方法中拋出RemoteException異常
package cn.wzh;
import java.rmi.*;
public interface Converter extends Remote
{
public double rmb2Dollar(double rmb) throws RemoteException;
}
2、定義遠程接口的實現類(ConverterImpl.java)
遠程接口必須實現服務接口並且繼承java.rmi.server.UnicastRemoteObject對象,構造方法必須拋出RemoteException
package cn.wzh;
import java.rmi.*;
import java.rmi.server.*;public class ConverterImpl extends UnicastRemoteObject implements Converter
{
public ConverterImpl() throws RemoteException
{
super();
}
public double rmb2Dollar(double rmb)
{
return rmb * 0.125;
}
}
3、編寫RMI服務器端代碼(RMIServer.java)
出於對RMI調用的安全考慮,需要對RMI應用設置安全管理器。使用命名綁定關鍵字到對象。
package cn.wzh;
import java.rmi.*;
public class RMIServer
{
// 由於這裏測試我們是最終用戶,所以直接將異常拋給虛擬機
public static void main(String[] args) throws Exception
{
System.setSecurityManager(new RMISecurityManager());
Converter c = new ConverterImpl();
Naming.bind("convert", c);
System.out.println("rmi server start ...");
}
}
4、編寫RMI客戶端調用類(RMIClient.java)
package cn.wzh;
import java.rmi.*;
import java.net.MalformedURLException;public class RMIClient
{
// 同樣爲了方便,直接異常拋出
public static void main(String[] args) throws Exception
{
System.setSecurityManager(new RMISecurityManager());
try
{
// 這裏因爲是在本地所以省略了地址跟協議,若在網絡中的遠程方法調用,需要這樣寫
// Converter c = (Converter)Naming.lookup("rmi://192.168.0.13/convert");
Converter c = (Converter)Naming.lookup("convert");
double rmb = c.rmb2Dollar(1000);
System.out.println("converter result : " + rmb);
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
catch (RemoteException e)
{
e.printStackTrace();
}
catch (NotBoundException e)
{
e.printStackTrace();
}
}
}
5、整體編譯代碼
javac –d . *.java
6、編譯生成stub
stub是什麼,stub是java爲rmi提供的封裝你遠程調用底層的一些細節處理(如socket和序列化操作),使你只需要去處理業務的實現而不必關注與底層網絡的處理(有興趣可以反編譯去看看它是如何實現的,其實也很簡單)。
rmic cn.wzh.ConverterImpl
其中rmic是RMI編譯器,ConverterImpl爲遠程接口實現類名,它是編譯過的class文件。
遠程方法實現接口類(ConverterImpl)生成的stub名字規定爲 `ConverterImpl` + `_stub`(ConverterImpl_stub.class)。
7、啓動RMI服務器(RMIServer)
java cn.wzh.RMIServer
若出現這樣的異常
需要在編寫權限文件(Converter.policy),這裏不對權限文件做太多講解,我將會另外用一邊文章來講解權限文件。
內容爲:
grant {
permission java.security.AllPermission;
};
再次編譯運行,注意-D傳入權限文件位置
java -Djava.security.policy=cn/wzh/converter.policy cn.wzh.RMIServer
不好意思,又一次運行出錯
這是因爲你本地java RMI服務器沒有啓動,現在就啓動吧
start rmiregistry
再次運行 java -Djava.security.policy=cn/wzh/converter.policy cn.wzh.RMIServer
終於是啓動成功了,那麼開始運行RMI客戶端。
8、運行RMI客戶端
值得注意的是RMI客戶端也需要加入權限文件的位置,不然也會拋出權限異常。
java -Djava.security.policy=cn/wzh/converter.policy cn.wzh.RMIClient