RMI介绍
??远程方法调用(Remote Method Invocation)
是Sun公司规定的允许在不同的JAVA虚拟机之间进行对象间通信的一种规范。在RMI中,JVM可以位于一个或多个计算机上,其中一个JVM可以调用存储在另一个JVM中的对象方法。这就使得应用程序可以远程调用其他对象方法,从而达到分布式计算的目的,以共享各个系统的资源和处理能力。
??除了RMI外,基于JAVA的实现不同JAVA虚拟机上的应用程序之间通信技术主要有两种:套接字
和JAVA消息服务(JMS)
。
??使用套接字是实现程序间通信的最为灵活和强大的方式。但是它必须通过应用级协议进行通信,要求应用程序之间使用同样的协议,并且要求设计通信过程中的错误判断等。
??JMS
和RMI
的区别在于,采用JMS服务,对象是物理上被异步地从网络的某个JVM上直接移动到另一个JVM上。而RMI对象是绑定在本地JVM上,只有函数参数和返回值是通过网络传送的。
RMI开发应用程序的一般步骤
- 定义远程接口
- 实现这个远程接口
- 生成
stub
(客户代理)和skeleton
(服务器实体)
- 编写使用远程对象的客户程序
- 启动注册表并登记远程对象
- 运行服务器和客户程序
Eclipse中RMI环境搭建
- 首先下载Eclipse的RMI开发插件 下载地址:http://www.genady.net/rmi/v20/downloads.html
- 解压缩将net.genady.rmi_2.5.0文件夹下的两个文件拷贝到eclipse安装目录下,覆盖同名的两个文件夹
- 重启eclipse即可在快捷栏看到RMI插件标志

简单实例
定义远程接口
1 2 3 4 5 6 7 8
| package RMIinterface;
import java.rmi.Remote; import java.rmi.RemoteException;
public interface extends Remote{ public String sayHello ()throws RemoteException; }
|
创建一个远程接口时,必须遵守下列规则:
- 远程接口必须为public
- 远程接口必须继承java.rmi.Remote 除应用程序本身有关异常外,
- 远程接口中的每个方法都必须在自己的 throws中声明java.rmi.RemoteException
- 作为参数或返回值传递的一个远程对象,必须声明为远程接口,不可 声明为实现类。
实现这个接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package rmiIMP;
import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject;
import RMIinterface.iHello;
public class rmiIMP extends UnicastRemoteObject implements {
private static final long serialVersionUID = 1L;
public rmiIMP() throws RemoteException { }
public String sayHello() throws RemoteException { return "hello zhang"; }
}
|
构建服务器程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package rmiServer;
import java.net.MalformedURLException; import java.rmi.AlreadyBoundException; import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry;
import rmiIMP.rmiIMP; import RMIinterface.iHello;
public class helloServer {
public static void main(String[] args) { try { iHello ihello = new rmiIMP(); LocateRegistry.createRegistry(1099); Naming.bind("rmi://localhost:1099/iHello",ihello); } 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(); } }
}
|
构建客户程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package rmiClient;
import java.net.MalformedURLException; import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.RemoteException;
import RMIinterface.iHello;
public class helloClient {
public static void main(String[] args) { try { iHello ihello = (iHello) Naming.lookup("rmi://localhost:1099/iHello"); System.out.println(ihello.sayHello()); } catch (MalformedURLException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } catch (NotBoundException e) { e.printStackTrace(); } }
}
|
打开cmd窗口,对所在位置的接口进行编译。
右键该项目,打开运行配置窗口,找到RMI VM Properties
后,对java.security.policy
与java.rmi.server.codebase
进行配置

然后在RMI Application方式下运行服务器程序,在Java Application方式下运行客户程序。
结合XML编程的RMI实例——航班信息查询(通过查询目的地显示到达该目的地的所有航班信息)
编写多个XML文件,每个XML文件表示一所航空公司。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <?xml version="1.0" encoding="GB2312"?> <!DOCTYPE 航班列表 [ <!ELEMENT 航班列表 (航班)*> <!ELEMENT 航班 (编号,始发地,目的地,出发时间,到达时间)> <!ELEMENT 编号 (#PCDATA)> <!ELEMENT 始发地 (#PCDATA)> <!ELEMENT 目的地 (#PCDATA)> <!ELEMENT 出发时间 (#PCDATA)> <!ELEMENT 达到时间 (#PCDATA)> ]> <航班列表> <航班> <编号>101</编号> <始发地>武汉</始发地> <目的地>北京</目的地> <出发时间>2016-05-02 16:30</出发时间> <到达时间>2016-05-02 19:25</到达时间> </航班> <航班> <编号>102</编号> <始发地>深圳</始发地> <目的地>成都</目的地> <出发时间>2016-05-03 10:15</出发时间> <到达时间>2015-05-03 14:00</到达时间> </航班> <航班> <编号>103</编号> <始发地>北京</始发地> <目的地>天津</目的地> <出发时间>2016-05-02 16:30</出发时间> <到达时间>2016-05-02 19:25</到达时间> </大专栏 Java中间件之RMI及实例介绍 · zijian‘s blog"name">航班> </航班列表>
|
定义远程接口
1 2 3 4 5 6 7 8 9
| package searchF;
import java.rmi.Remote; import java.rmi.RemoteException;
public interface SearchFlight extends Remote{ public void SearchF()throws RemoteException;
}
|
实现这个远程接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| package searchIMP;
import java.io.File; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.Scanner;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList;
import searchF.SearchFlight;
public class searchFIMP extends UnicastRemoteObject implements SearchFlight{
private static final long serialVersionUID = 1L;
public searchFIMP() throws RemoteException { super(); }
public void SearchF() throws RemoteException { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); System.out.print("请输入您要查询的目的地:"); Scanner scan = new Scanner(System.in); String city = scan.nextLine(); scan.close(); int[] temp = new int[3]; int[] count = new int[3]; for(int k = 0 ; k < 3; k++){ String airport = "flight"+ (k+1) +".xml"; Document document = builder.parse(new File(airport)); NodeList nodelist = document.getElementsByTagName("航班"); temp[k] = nodelist.getLength(); count[k] = 0; for (int i = 0; i < nodelist.getLength(); i++) { NodeList nl = nodelist.item(i).getChildNodes(); if(getFlight(nl, city)) { if(k == 0 && count[k] == 0) System.out.println("到达该目的地的所有航班信息如下:"); count[k] ++; for (int j = 0; j < nl.getLength(); j++) { Node cnode = nl.item(j); if (cnode.getNodeType() == Node.ELEMENT_NODE) { System.out.println(" -->" + cnode.getNodeName() + ": " + cnode.getTextContent()); } } System.out.println(); }else temp[k]--; } } if(temp[0] + temp[1] + temp[2] == 0 ) System.out.println("没有到达该目的地的航班信息!"); else{ int sum = count[0]+count[1]+count[2]; System.out.println("共有"+ sum + "条航班信息!"); } } catch (Exception e) { e.printStackTrace(); } } public static boolean getFlight(NodeList nodelist, String str) { boolean temp = false; for (int i = 0; i < nodelist.getLength(); i++) { Node node = nodelist.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { if (node.getTextContent().equals(str) && node.getNodeName().equals("目的地")) { temp = true; } } } return temp; } }
|
构建服务器程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package searchServer;
import java.net.MalformedURLException; import java.rmi.AlreadyBoundException; import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import searchF.SearchFlight; import searchIMP.searchFIMP;
public class searchFServer {
public static void main(String[] args) { try { searchFIMP imp = new searchFIMP(); LocateRegistry.createRegistry(1099); Naming.bind("rmi://localhost:1099/searchFIMP",imp); } catch (RemoteException e) { System.out.println("创建远程对象异常!"); e.printStackTrace(); } catch (MalformedURLException e) { System.out.println("URL异常!"); e.printStackTrace(); } catch (Exception e){ e.printStackTrace(); } } }
|
构建客户程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package searchClient;
import java.net.MalformedURLException; import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.RemoteException; import searchF.SearchFlight;
public class searchFClient {
public static void main(String[] args) { try { SearchFlight searchF = (SearchFlight) Naming.lookup("rmi://localhost:1099/searchFIMP"); searchF.SearchF(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } catch (NotBoundException e) { e.printStackTrace(); } }
}
|
以RMI Application方式运行服务器程序,正常运行客户端程序,运行结果如下:
Java中间件之RMI及实例介绍 · zijian‘s blog
原文:https://www.cnblogs.com/lijianming180/p/12239639.html