头几天有一个小学妹找我帮她写实验报告,内容一大堆,主要是利用RMI实现通信,RMI我以前一直没有用过,这次也算学习了,就把心得写出来,网上主要都是如何用RMI写代码,但是在eclipse下开发RMI和详细解释不是很多,我就把我主要理解的一些东西写出来把。

        先展示一下本人用命令行运行的代码流程和解释,我也是参考人家的。

Java RMI 简介

      远程方法调用( RMI,Remote Method Invocation)是jdk1.1中引入的分布式对象软件包,它的出现大大简化了分布异构环境中Java应用之间的通信。
      要使用RMI,必须构建四个主要的类:远程对象的本地接口、远程对象实现、RMI客户机和RMI服务器。RMI服务器生成远程对象实现的一个实例,并用一个专有的URL注册。RMI客户机在远程RMI服务器上查找服务对象,并将它转换成本地接口类型,然后像对待一个本地对象一样使用它。
          下面是一个简单的RMI实例,RMI客户机通过RMI服务器提供的方法输出一个语句。例子虽然很简单,但掌握了Java RMI调用的基本原理和方法,在实现复杂应用时,我们需要做的也只是完善远程对象的实现类而已。
 
 
RMI 实例分析
 
1. 远程对象的本地接口声明(RMIOperate.java) 

   · 该类仅仅是一个接口声明, RMI客户机可以直接使用它,RMI服务器必须通过一个远程对象来实现它,并用某个专有的URL注册它的一个实例。 
   · 远程接口扩展 java.rmi.Remote 接口。
   · 除了所有应用程序特定的例外之外,每个方法还必须在  throws 子句中声明 java.rmi.RemoteException(或 RemoteException 的父类)。
 
    
  1. Hello.java  
  2. /* * @author javamxj (CSDN Blog) 创建日期 2004-12-27 */   
  3. import java.rmi.*; // RMI本地接口必须从Remote接口派生   
  4. public interface Hello extends Remote { // 接口中的具体方法声明,注意必须声明抛出RemoteException  
  5.  String sayHello(String name) throws RemoteException; }  

 2.远程对象实现类

       这个类应实现RMI客户机调用的远程服务对象的本地接口,它必须从UnicastRemoteObject继承,构造函数应抛出RemoteException异常。 

 

 
    
  1.  HelloImpl.java  
  2.    
  3. /*  
  4.  * @author javamxj (CSDN Blog) 创建日期 2004-12-27  
  5.  */ 
  6. import java.rmi.*;  
  7. import javax.rmi.PortableRemoteObject;  
  8. public class HelloImpl extends PortableRemoteObject implements Hello {  
  9.     /* 构造函数 */ 
  10.     public HelloImpl() throws RemoteException {  
  11.         super();  
  12.     }  
  13.     /* 实现本地接口中声明的'sayHello()'方法 */ 
  14.     public String sayHello(String message) throws RemoteException {  
  15.         System.out.println("我在RMI的服务器端,客户端正在调用'sayHello'方法。 ");  
  16.         System.out.println("Hello  " + message);  
  17.         return message;  
  18.     }  

 3.RMI服务器类

   该类创建远程对象实现类HelloImpl的一个实例,然后通过一个专有的URL来注册它。所谓注册就是通过Java.rmi.Naming.bind()方法或Java.rmi.Naming.rebind()方法,将HelloImpl实例绑定到指定的URL上。

 
 
    
  1.  HelloServer.java  
  2. /*  
  3.  * @author javamxj (CSDN Blog) 创建日期 2004-12-27  
  4.  */ 
  5. import java.rmi.*;  
  6. public class HelloServer {  
  7.     public static void main(String[] args) {  
  8.         // 在服务器端设置安全机制           
  9.         /*  
  10.            if (System.getSecurityManager() == null) {  
  11.                System.setSecurityManager(new RMISecurityManager());   
  12.            }  
  13.         */           
  14.         try {  
  15.             System.out.println("开始 RMI Server ...");  
  16.             /* 创建远程对象的实现实例 */ 
  17.             HelloImpl hImpl = new HelloImpl();  
  18.             System.out.println("将实例注册到专有的URL ");  
  19.             Naming.rebind("HelloService", hImpl);  
  20.               
  21.             System.out.println("等待RMI客户端调用...");  
  22.             System.out.println("");  
  23.         } catch (Exception e) {  
  24.             System.out.println("错误: " + e);  
  25.         }  
  26.     }  

 请注意有关 rebind 方法调用的下列参数:

  • 第一个参数是 URL 格式的 java.lang.String,表示远程对象的位置和名字。 
    • 需要将 myhost 的值更改为服务器名或 IP 地址。否则,如果在 URL 中省略,则主机缺省值为当前主机,而且在 URL 中无需指定协议(例如“HelloServer”)。 
    • 在 URL 中,可以选择提供端口号:例如“//myhost:1234/HelloServer”。端口缺省值为 1099。除非服务器在缺省 1099 端口上创建注册服务程序,否则需要指定端口号。 
  • 第二个参数为从中调用远程方法的对象实现引用。 
  • RMI 运行时将用对远程对象 stub 程序的引用代替由 hImpl 参数指定的实际远程对象引用。远程实现对象(如 HelloImpl 实例)将始终不离开创建它们的虚拟机。因此,当客户机在服务器的远程对象注册服务程序中执行查找时,将返回包含该实现的 stub 程序的对象。 
4.RMI 客户机类 

   · RMI客户使用 java.rmi.Naming.lookup()方法,在指定的远程主机上查找RMI服务对象,若找到就把它转换成本地接口RMIOperate类型。它与CORBA不同之处在于RMI客户机必须知道提供RMI服务主机的URL,这个URL可以通过rmi://host/path或rmi://host:port/path来指定,如果省略端口号,就默认使用1099。 
   · Java.rmi.Naming.lookup()方法可能产生三个异常: Java.rmi.RemoteException、Java.rmi.NotBoundException、java.net. MalformedURLException,三个异常都需要捕获。

 

 
    
  1. HelloClient.java  
  2. /*  
  3.  * @author javamxj (CSDN Blog) 创建日期 2004-12-27  
  4.  */ 
  5. import java.rmi.*;  
  6. public class HelloClient {  
  7.     public static void main(String[] args) {  
  8.         //   在服务器端设置安全机制           
  9.         /*  
  10.            if (System.getSecurityManager() == null) {  
  11.                System.setSecurityManager(new RMISecurityManager());   
  12.            }  
  13.         */       
  14.         /* 默认为本地主机和默认端口 */ 
  15.         String host = "localhost:1099";  
  16.         /* 带输入参数时,将host设置为指定主机 */ 
  17.         if (args.length > 0)  
  18.             host = args[0];  
  19.         try {  
  20.             /* 根据指定的URL定位远程实现对象 */ 
  21.             /* “h”是一个标识符,我们将用它指向实现“Hello”接口的远程对象 */ 
  22.             Hello h = (Hello) Naming.lookup("rmi://" + host + "/HelloService");  
  23.               
  24.             System.out.println("实现“Hello”接口的远程对象: " + h);  
  25.             System.out.println("我在客户端,开始调用RMI服务器端的'sayHello'方法");  
  26.             System.out.println("欢迎,  " + h.sayHello("javamxj blog"));  
  27.         } catch (Exception ex) {  
  28.             System.out.println("错误 " + ex);  
  29.         }  
  30.     }  
  31. }  

 

5.  编译代码与运行系统:
 
   在 MS-DOS环境下,创建一个D:\RMISample目录,把上面4个文件复制到这个目录下,然后在此目录下新建两个文件夹:client和server(把它们分别看作是客户端与服务端)。
 
(1).编译所有的源代码
    D:\RMISample> javac *.java

(2).生成客户端存根和服务器框架
    D:\RMISample> rmic HelloImpl
    这将生成 HelloImpl_Stub.class和HelloImpl_Skel.class。
   (  :如果需要查看这两个类的源代码,可以使用 “ rmic -keep HelloImpl”语句)
 
(3).把 Hello.class、HelloClient.class、HelloImpl_Stub.class复制到client目录;
    把 Hello.class、HelloServer.class、HelloImpl_Skel.class、HelloImpl_Stub.class 复制到server目录。
 
(4).启动 RMI注册
    D:\RMISample\server>rmiregistry
   (注:我是在命令控制台下运行这个系统的,必须开启三个控制台窗口,一个运行 RMIRegistry,一个运行服务器,还有一个运行客户端。)
 
(5).运行和调用

● 在服务器上执行 HelloServer
  D:\RMISample\server>java HelloServer
 
● 在本地客户机上运行 HelloClient
  D:\RMISample\client>java HelloClient
● 在远程客户机上运行 HelloClient(须指明RMI服务器主机名或IP地址)
   java HelloClient  222.222.34.34
 
运行 rmiregistry和server后的结果:

 再运行 Client后的结果:

   还有一点要注意,在上面的例子中我注释了安全管理的代码,如果把注释去掉,那么需要建立一个安全策略文件,比如其文件名为  policy.txt,内容如下:
grant {
permission java.security.AllPermission "", "";
};
这是一条简单的安全策略 ,它允许任何人做任何事,对于你的更加关键性的应用,你必须指定更加详细安全策略。把这个文件复制到Client和Server目录,然后如下运行:
D:\RMISample\server>java -Djava.security.policy=policy.txt HelloServer
D:\RMISample\client>java -Djava.security.policy=policy.txt HelloClient
 
以上是别人在网上总结的过程,但是不是在eclipse下运行,一下是我自己在eclipse运行过程。
一、安装插件包     Eclipse RMI插件下载地址是http://www.genady.net/rmi/v16/ 
将解压后得到的features和plugins文件夹拷贝至Eclipse安装根目录下,覆盖原有文件夹。  我自己已下载到插件包,在附件里面     启动Eclipse(如果已经启动,请重新启动Eclipse),这时在工具栏上会发现多了一个工具图标,里面有Registry的管理选项,这个就是RMI Registry的管理器。说明已经安装成功了。

二、设置开发环境       

         在安装好插件包后,我们来设置RMI开发环境。启动Eclipse,在菜单window->preferences对话框中,选中左边树菜单java->rmi,右边窗口会出现RMI Plugin的默认设置信息。       最上面的Path to RMI registry设置java的RMI Registry的路径,如这里设置的是C:/Program Files/Java/jdk1.5.0_05/bin/rmiregistry.exe,一般不用管它。下面的一个框是RMI的服务端口,默认是 1099,这个类似tomcat的服务端口8080一样,链接的时候需要找到对应的端口才能链接上。其实RMI的最低层是socket。  这里需要特别指出的是RMI Plugin是个收费的Eclipse插件,有15天的免费试用期。而RMI属性中最大的窗口就是填使用授权信息的。

这也就是开发环境的基本设置,主要是需要RMI的插件和设置。

三、运行调试项目

       在运行之前需要进行一下设置,否则,会提示错误信息,说找不到stub类。

        1、启动RMIRegistry

        Eclipse菜单window->show view->others,在弹出菜单中选择RMI Views>RMI Registry Inspector,这是会多出来一个窗口,这里可以显示已经注册的RMI应用。点击工具条上的RMI Plugin图标,在菜单中选择Start Local Registry。注意这个只需要启动一次,除非你把它关掉。

      2、配置运行RMI服务  右键点击左边树中的RMI_Server.java文件,菜单Debug As ->RMI Application。在弹出对话框中找到RMI Properties标签页。   这时这里前两项显示红色。   选中java.security.police项的value框,点击选择按钮会出现文件选择对话框,我们这里设置成C:/Program Files/Java/jre1.5.0_05/lib/security/java.security。就是jre的安全策略配置文件,要选择成泥当前用的jdk的侧略文件。选中第二项java.rmi.server.codebase的value项,这里选择编译后类包所在的文件夹。点击选择按钮->add按钮->pick from workspace,选择当前工程RMITest的bin文件夹。这里是file:/E:/workspace/RMITest/bin/。(这里有点要补充一下,还可以 点击选择按钮->add按钮->compute from classpath)。

以上是运行RMI Application,但是我的电脑没显示RMI Application,当时这个窗口也显示不到任何RMI项目

这时无法启动RMIRegistry ,因此只能手动启动RMIRegistry 

这里启动完成RMI注册,并且会在工程的bin路径下生成先关的stub类。在运行服务器类和客户端类就完成了。注意这个RMI注册只只能启动一次,除非你把它关掉。