Java RMI及实例介绍

一. RMI介绍

  远程方法调用(Remote Method Invocation, RMI )是Sun公司规定的允许在不同的JAVA虚拟机之间进行对象间通信的一种规范。在RMI中,JVM可以位于一个或多个计算机上,其中一个JVM可以调用存储在另一个JVM中的对象方法。这就使得应用程序可以远程调用其他对象方法,从而达到分布式计算的目的,以共享各个系统的资源和处理能力。

  除了RMI外,基于JAVA的实现不同JAVA虚拟机上的应用程序之间通信技术主要有两种:套接字和JAVA消息服务 (JMS)。

  使用套接字是实现程序间通信的最为灵活和强大的方式。但是它必须通过应用级协议进行通信,要求应用程序之间使用同样的协议,并且要求设计通信过程中的错误判断等。

  JMS和RMI的区别在于,采用JMS服务,对象是物理上被异步地从网络的某个JVM上直接移动到另一个JVM上。而RMI对象是绑定在本地JVM上,只有函数参数和返回值是通过网络传送的。

 

 二. RMI开发应用程序的一般步骤:

  1. 定义远程接口
  2. 实现这个远程接口
  3. 生成stub(客户代理) 和 skeleton(服务器实体)
  4. 编写使用远程对象的客户程序。
  5. 启动注册表并登记远程对象
  6. 运行服务器和客户程序

三. Eclipse 编程环境搭建

   安装RMI插件:

  1、首先下载Eclipse的RMI开发插件 下载地址:http://www.genady.net/rmi/v20/downloads.html

  2、解压缩将net.genady.rmi_2.5.0文件夹下的两个文件拷贝到eclipse安装目录下,覆盖同名的两个文件夹

  3、重启eclipse即可在快捷栏看到RMI插件标志  

 

四. 简单实例

      1. 定义远程接口

1 package RMIinterface;
2 
3 import java.rmi.Remote;
4 import java.rmi.RemoteException;
5 
6 public interface iHello extends Remote{
7     public String sayHello ()throws RemoteException;
8 }
View Code

  创建一个远程接口时,必须遵守下列规则:

    1. 远程接口必须为public

    2. 远程接口必须继承java.rmi.Remote 除应用程序本身有关异常外,

    3. 远程接口中的每个方法都必须在自己的 throws中声明java.rmi.RemoteException

    4. 作为参数或返回值传递的一个远程对象,必须声明为远程接口,不可 声明为实现类。

  2. 实现这个接口

 1 package rmiIMP;
 2 
 3 import java.rmi.RemoteException;
 4 import java.rmi.server.UnicastRemoteObject;
 5 
 6 import RMIinterface.iHello;
 7 
 8 public class rmiIMP extends  UnicastRemoteObject implements iHello{
 9 
10     private static final long serialVersionUID = 1L;
11 
12     public rmiIMP() throws RemoteException {
13     }
14 
15     @Override
16     public String sayHello() throws RemoteException {
17         return "hello zhang";
18     }
19     
20     
21 
22 }
View Code

  3. 构建服务器程序

 1 package rmiServer;
 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 rmiIMP.rmiIMP;
10 import RMIinterface.iHello;
11 
12 public class helloServer {
13 
14     public static void main(String[] args) {
15         
16         try {
17             iHello ihello = new rmiIMP();
18             LocateRegistry.createRegistry(1099); 
19             Naming.bind("rmi://localhost:1099/iHello",ihello);
20             
21             
22         } catch (RemoteException e) {
23             System.out.println("创建远程对象异常!");
24             e.printStackTrace();
25         } catch (MalformedURLException e) {
26             System.out.println("URL异常!");
27             e.printStackTrace();
28         } catch (AlreadyBoundException e) {
29             System.out.println("绑定异常!");
30             e.printStackTrace();
31         }
32         
33     }
34 
35 }
View Code

  4.构建客户程序

 1 package rmiClient;
 2 
 3 import java.net.MalformedURLException;
 4 import java.rmi.Naming;
 5 import java.rmi.NotBoundException;
 6 import java.rmi.RemoteException;
 7 
 8 import RMIinterface.iHello;
 9 
10 public class helloClient {
11 
12     public static void main(String[] args) {
13         try {
14             iHello ihello = (iHello) Naming.lookup("rmi://localhost:1099/iHello");
15             System.out.println(ihello.sayHello());    
16             
17             
18         } catch (MalformedURLException e) {
19             e.printStackTrace();
20         } catch (RemoteException e) {
21             e.printStackTrace();
22         } catch (NotBoundException e) {
23             e.printStackTrace();
24         }
25     }
26 
27 }
View Code

  5.进入cmd,对所在位置的接口进行编译。

  6.右键该项目,打开运行配置窗口,找到RMI VM Properties后,对java.security.policy与java.rmi.server.codebase进行配置

  

  7. 然后在RMI Application方式下运行服务器程序,在Java Application方式下运行客户程序。

 

五. 结合XML编程的RMI实例——航班信息查询(通过查询目的地显示到达该目的地的所有航班信息)

  1.编写多个XML文件,每个XML文件表示一所航空公司。

 1 <?xml version="1.0" encoding="GB2312"?>
 2 <!DOCTYPE 航班列表 [
 3     <!ELEMENT 航班列表 (航班)*>
 4     <!ELEMENT 航班 (编号,始发地,目的地,出发时间,到达时间)>
 5     <!ELEMENT 编号 (#PCDATA)>
 6     <!ELEMENT 始发地 (#PCDATA)>
 7     <!ELEMENT 目的地 (#PCDATA)>
 8     <!ELEMENT 出发时间 (#PCDATA)>
 9     <!ELEMENT 达到时间 (#PCDATA)>
10 ]>
11 <航班列表>
12     <航班>
13        <编号>101</编号>
14        <始发地>武汉</始发地>
15        <目的地>北京</目的地>
16        <出发时间>2016-05-02 16:30</出发时间>
17        <到达时间>2016-05-02 19:25</到达时间>
18     </航班>
19     <航班>
20        <编号>102</编号>
21        <始发地>深圳</始发地>
22        <目的地>成都</目的地>
23        <出发时间>2016-05-03 10:15</出发时间>
24        <到达时间>2015-05-03 14:00</到达时间>
25     </航班>
26     <航班>
27        <编号>103</编号>
28        <始发地>北京</始发地>
29        <目的地>天津</目的地>
30        <出发时间>2016-05-02 16:30</出发时间>
31        <到达时间>2016-05-02 19:25</到达时间>
32     </航班>
33 </航班列表>
View Code

  2.定义远程接口

1 package searchF;
2 
3 import java.rmi.Remote;
4 import java.rmi.RemoteException;
5 
6 public interface SearchFlight extends Remote{
7     public void SearchF()throws RemoteException;
8 
9 }
View Code

  3.实现这个远程接口

 1 package searchIMP;
 2 
 3 import java.io.File;
 4 import java.rmi.RemoteException;
 5 import java.rmi.server.UnicastRemoteObject;
 6 import java.util.Scanner;
 7 
 8 import javax.xml.parsers.DocumentBuilder;
 9 import javax.xml.parsers.DocumentBuilderFactory;
10 
11 import org.w3c.dom.Document;
12 import org.w3c.dom.Node;
13 import org.w3c.dom.NodeList;
14 
15 import searchF.SearchFlight;
16 
17 public class searchFIMP extends  UnicastRemoteObject implements SearchFlight{
18 
19 
20     private static final long serialVersionUID = 1L;
21 
22     public searchFIMP() throws RemoteException {
23         super();
24     }
25 
26     @Override
27     public void SearchF() throws RemoteException {
28         try {
29             //使用DOM解析XML文件
30             //获得一个XML文件的解析器
31             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
32             //解析XML文件生成DOM文档的接口类,以便访问DOM
33             DocumentBuilder builder = factory.newDocumentBuilder();
34             System.out.print("请输入您要查询的目的地:");    
35             Scanner scan = new Scanner(System.in);
36             String city = scan.nextLine();
37             scan.close();
38             int[] temp = new int[3];
39             int[] count = new int[3];
40             for(int k = 0 ; k < 3; k++){
41                 String airport = "flight"+ (k+1) +".xml";
42                 //Document接口描述了对应于整个XML文件的文档树
43                 Document document = builder.parse(new File(airport));
44                 //获取“航班”元素的子节点列表
45                 NodeList nodelist = document.getElementsByTagName("航班");
46                 temp[k] = nodelist.getLength();
47                 count[k] = 0;
48                 for (int i = 0; i < nodelist.getLength(); i++) {
49                     NodeList nl = nodelist.item(i).getChildNodes();
50                     if(getFlight(nl, city)) {
51                         if(k == 0 && count[k] == 0)
52                             System.out.println("到达该目的地的所有航班信息如下:");
53                         count[k] ++;
54                         for (int j = 0; j < nl.getLength(); j++) {
55                             Node cnode = nl.item(j);
56                             if (cnode.getNodeType() == Node.ELEMENT_NODE) {
57                                 System.out.println("  -->" + cnode.getNodeName() + ": " + cnode.getTextContent());
58                             }
59                         }
60                         System.out.println();
61                     }else
62                         temp[k]--;
63                 }
64             }
65                 if(temp[0] + temp[1] + temp[2] == 0 )
66                     System.out.println("没有到达该目的地的航班信息!");
67                 else{
68                     int sum = count[0]+count[1]+count[2];
69                     System.out.println("共有"+ sum + "条航班信息!");
70                 }
71         }
72          catch (Exception e) {
73             e.printStackTrace();
74         }
75     }
76     
77     //判断所当前航班的目的地城市是否为所查询城市,若是,则返回true
78     public static boolean getFlight(NodeList nodelist, String str) {
79         boolean temp = false;
80         for (int i = 0; i < nodelist.getLength(); i++) {
81             Node node = nodelist.item(i);
82             if (node.getNodeType() == Node.ELEMENT_NODE) {
83                 if (node.getTextContent().equals(str) && node.getNodeName().equals("目的地")) {
84                     temp = true;
85                 }
86             }
87         }
88         return temp;
89     }
90 }
View Code

  4.构建服务器程序

 1 package searchServer;
 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 import searchF.SearchFlight;
 9 import searchIMP.searchFIMP;
10 
11 public class searchFServer {
12 
13     public static void main(String[] args) {
14         try {
15             searchFIMP imp = new searchFIMP();
16             LocateRegistry.createRegistry(1099); 
17             Naming.bind("rmi://localhost:1099/searchFIMP",imp);
18             
19         } catch (RemoteException e) {
20             System.out.println("创建远程对象异常!");
21             e.printStackTrace();
22         } catch (MalformedURLException e) {
23             System.out.println("URL异常!");
24             e.printStackTrace();
25         } catch (Exception e){
26             e.printStackTrace();
27         }
28     }
29 }
View Code

  5.构建客户程序

 1 package searchClient;
 2 
 3 import java.net.MalformedURLException;
 4 import java.rmi.Naming;
 5 import java.rmi.NotBoundException;
 6 import java.rmi.RemoteException;
 7 import searchF.SearchFlight;
 8 
 9 public class searchFClient {
10 
11     public static void main(String[] args) {
12         try {
13                 SearchFlight searchF = (SearchFlight) Naming.lookup("rmi://localhost:1099/searchFIMP");
14                 searchF.SearchF();    
15             
16             
17         } catch (MalformedURLException e) {
18             e.printStackTrace();
19         } catch (RemoteException e) {
20             e.printStackTrace();
21         } catch (NotBoundException e) {
22             e.printStackTrace();
23         }
24     }
25 
26 }
View Code

   6.以RMI Application方式运行服务器程序,正常运行客户端程序,运行结果如下:

  

 

 

posted @ 2016-05-18 12:04  小z1情调  阅读(250)  评论(0编辑  收藏  举报