一、什么是RMI
Java遠程方法調用,即Java RMI(Java Remote Method Invocation)是Java編程語言里,一種用於實現遠程過程調用的應用程序編程接口。它使客戶機上運行的程序可以調用遠程服務器上的對象。遠程方法調用特性使Java編程人員能夠在網絡環境中分布操作。RMI全部的宗旨就是盡可能簡化遠程接口對象的使用。
Java RMI極大地依賴於接口。在需要創建一個遠程對象的時候,程序員通過傳遞一個接口來隱藏底層的實現細節。客戶端得到的遠程對象句柄正好與本地的根代碼連接,由后者負責透過網絡通信。這樣一來,程序員只需關心如何通過自己的接口句柄發送消息。
接口的兩種常見實現方式是:最初使用JRMP(Java Remote Message Protocol,Java遠程消息交換協議)實現;此外還可以用與CORBA兼容的方法實現。RMI一般指的是編程接口,也有時候同時包括JRMP和API(應用程序編程接口),而RMI-IIOP則一般指RMI接口接管絕大部分的功能,以支持CORBA的實現。
最初的RMI API設計為通用地支持不同形式的接口實現。后來,CORBA增加了傳值(pass by value)功能,以實現RMI接口。然而RMI-IIOP和JRMP實現的接口並不完全一致。
二、基本原理
要實現網絡機器間的通訊,首先得來看看計算機系統網絡通信的基本原理,在底層層面上來看,網絡通信需要做的就是將流從一台計算機傳輸到另一台計算機,基於傳輸協議和網絡IO來實現,其中傳輸協議比較出名的有HTTP、TCP、UDP等等,HTTP、TCP、UDP都是基於sokect概念上為某種應用場景而擴展出的傳輸協議,網絡IO,主要有bio、nio、aio三種方式,所有的分布式應用通訊都是基於這個原理而實現的,只是為了應用的易用,各種語言通常都會提供一些更為貼切應用易用的應用層協議。
三、開發步驟
1、編寫遠程服務接口,該接口必須繼承 java.rmi.Remote 接口,方法必須拋出 java.rmi.RemoteException 異常;
2、編寫遠程接口實現類,該實現類必須繼承 java.rmi.server.UnicastRemoteObject 類;
3、運行RMI編譯器(rmic),創建客戶端 stub 類和服務端 skeleton 類;
4、啟動一個RMI注冊表,以便駐留這些服務;
5、在RMI注冊表中注冊服務;
6、客戶端查找遠程對象,並調用遠程方法;
四、實例代碼清單
1、創建遠程接口,繼承java.rmi.Remote接口
1 package com.cnblogs.javalouvre.service; 2 3 import java.rmi.RemoteException; 4 5 public interface GreetService extends java.rmi.Remote { 6 7 String sayHello(String name) throws RemoteException; 8 9 }
2、實現遠程接口,繼承 java.rmi.server.UnicastRemoteObject類
1 package com.cnblogs.javalouvre.service; 2 3 import java.rmi.RemoteException; 4 5 public class GreetServiceImpl extends java.rmi.server.UnicastRemoteObject implements GreetService { 6 7 private static final long serialVersionUID = 3434060152387200042L; 8 9 public GreetServiceImpl() throws RemoteException { 10 super(); 11 } 12 13 @Override 14 public String sayHello(String name) throws RemoteException { 15 return "Hello " + name; 16 } 17 18 }
3、生成Stub和Skeleton;
要生成Stub和Skeleton,首先需要編譯上述源文件得到類文件,然后執行rmic命令,具體如下
[root@oracle ~]#javac -source 1.6 -target 1.6 -d . *.java
[root@oracle ~]#rmic com.cnblogs.javalouvre.service.GreetServiceImpl
4、注冊服務
注冊服務執行rmiregistry命令,如下
[root@oracle ~]#rmiregistry
5、啟動服務
1 package com.cnblogs.javalouvre.server; 2 3 import java.net.MalformedURLException; 4 import java.rmi.AlreadyBoundException; 5 import java.rmi.Naming; 6 import java.rmi.RemoteException; 7 import java.rmi.registry.LocateRegistry; 8 9 import com.cnblogs.javalouvre.service.GreetServiceImpl; 10 11 public class Server { 12 13 public static void main(String[] args) { 14 try { 15 LocateRegistry.createRegistry(1098); 16 Naming.bind("rmi://10.108.1.138:1098/GreetService", new GreetServiceImpl()); 17 } catch (RemoteException e) { 18 e.printStackTrace(); 19 } catch (MalformedURLException e) { 20 e.printStackTrace(); 21 } catch (AlreadyBoundException e) { 22 e.printStackTrace(); 23 } 24 } 25 26 }
編譯、啟動服務
[root@oracle ~]#javac -source 1.6 -target 1.6 -d . Server.java
[root@oracle ~]#java -server com.cnblogs.javalouvre.server.Server
6、客戶端調用
1 package com.cnblogs.javalouvre.client; 2 3 import java.net.MalformedURLException; 4 import java.rmi.Naming; 5 import java.rmi.NotBoundException; 6 import java.rmi.RemoteException; 7 8 import com.cnblogs.javalouvre.service.GreetService; 9 10 public class Client { 11 12 public static void main(String[] args) { 13 try { 14 GreetService greetService = (GreetService) Naming.lookup("rmi://10.108.1.138:1098/GreetService"); 15 System.out.println(greetService.sayHello("Jobs")); 16 } catch (MalformedURLException e) { 17 e.printStackTrace(); 18 } catch (RemoteException e) { 19 e.printStackTrace(); 20 } catch (NotBoundException e) { 21 e.printStackTrace(); 22 } 23 } 24 25 }
編譯,執行
[root@oracle ~]#javac -source 1.6 -target 1.6 -d . Client.java
[root@oracle ~]#java -client com.cnblogs.javalouvre.client.Client
Hello Jobs