Java 远程方法调用------RMI技术

来源:互联网 发布:c语言 回车换行 编辑:程序博客网 时间:2024/06/07 02:33

RMI作为j2EE应用的主要技术之一,在分布式领域有着极强的生命力。正是因为rmi在分布式的应用能力,才让java渗透到除企业级应用的一些关键领域。比如云计算,hadoop的成功就是一个明显的例子。

       首先需要明白的是rmi的主要目标:rmi就是为非分布式程序的开发者设计了一套编写分布式程序的接口,方法。说白了,就是简化了编写分布式程序的步骤,降低了编写分布式程序的门槛。

       学习一个新的技术,就得学习他的新的特点,那么分布式编程与单机编程到底有什么样的区别,在哪些方面有区别。我们的考虑:对象怎样表现出它的行为,异常什么时候抛出、怎么抛出,内存是怎么管理的,参数是怎么从远程方法被传递、返回的。

下面就让我了解分布式与非分布式程序设计的区别,当你了解它们之间的区别后,相信你就能设计分布式的程序了,因为rmi能帮助你做很多底层的事情。

 本地对象远程对象对象的定义通过Java类定义本地对象远程对象对外的行为必须在接口中定义,继承Remote类对象的方法体通过Java类完成远程对象的行为由完成远程接口的类去执行对象的创建本地对象的实例创建由操作符new来完成远程对象的创建由远程主机的new 操作符完成。客户机不能直接new远程对象(除非使用Java 远程对象激活)对象访问本地对象通过对象引用直接访问远程对象通过对象引用访问,这个对象是指向远程接口实现的代理。引用在单虚拟机的环境中,一个对象的引用是直接指向堆内存的对象实例一个"远程引用"是本地堆内存中代理对象的指针。这个代理类包含允许连接远程对象的信息,而这个远程对象实现了所有的方法活动的引用在单虚拟机中,判断一个对象是不是"alive"是根据是不是还有引用指向该对象在分布式的环境当中,远程JVMs也许会崩溃,网络连接也可能断掉。判断一个远程对象是否还是活动状态是根据一段周期时间(最小的周期)内是不是有连接访问。如果所有的远程对象引用都明确的丢失,或所有远程对象引用超出租赁时间,那么,这时远程对象就可以被分布式垃圾回收器回收了Finalization如果一个对像实现了finalize()方法,那么它在垃圾回收器回收前调用如果一个远程对象实现了Unreferenced接口,那么这个Unreferenced方法在所有的远程引用都dropped的时候调用垃圾回收但所有的本地对象的引用都dropped的时候,这个对象就加入了垃圾回收器的候选队列里面分布式垃圾回收器与本地垃圾回收器协同工作。如果任何的远程对象引用和本地对象引用dropped,那么这个对象就和普通的对象一个成文垃圾回收器的候选异常运行时异常\编译时异常,Java编译器强制程序处理所有异常RMI强制所有程序必须处理任何可能抛出的RemoteException。这是为了保证分布式应用程序的健壮性。

 


Java与.NET都提供了远程处理功能,但不完全相同.Java远程处理是通过一个“共享接口”实现的,而.NET可以通过一个“共享命令集”实现。下面就这两种方式来具体说明。
   
   Java 远程处理 
   Java远程方法调用(RMI)提供了Java程序语言的远程通讯功能,这种特性使客户机上运行的程序可以调用远程服务器上的对象,使Java编程人员能够在网络环境中分布操作。 
   创建一个简单的Java分布式远程方法调用程序可以按以下几个步骤操作, 
   
   一、定义远程接口: 
   在 Java 中,远程对象是实现远程接口的类的实例, 远程接口声明每个要远程调用的方法。在需要创建一个远程对象的时候,我们通过传递一个接口来隐藏基层的实施细节,客户通过接口句柄发送消息即可。 
   远程接口具有如下特点: 
   1) 远程接口必须为public属性。如果不这样,除非客户端与远程接口在同一个包内,否则 当试图装入实现该远程接口的远程对象时,调用会得到错误结果。 
   2) 远程接口必须扩展接口java.rmi.Remote。 
   3) 除与应用程序本身特定的例外之外,远程接口中的每个方法都必须在自己的throws从句中 声明java.rmi.RemoteException。(或 RemoteException 的父类)。 
   4) 作为参数或返回值传递的一个远程对象(不管是直接,还是本地对象中嵌入)必须声明为远 程接口,而不应声明为实施类。 
   下面是远程接口的接口RmiSample的定义 
java 代码

 

  1. package com.robin.demo.rmi.interf;   
  2.   
  3. import java.rmi.Remote;   
  4. import java.rmi.RemoteException;   
  5.   
  6. public interface RmiSample extends Remote {   
  7.     public int sum(int a, int b) throws RemoteException;   
  8. }   

 二、实现远程接口: 
   远程对象实现类必须扩展远程对象java.rmi.UnicastRemoteObject类,并实现所定义的远程接口。远程对象的实现类中包含实现每个远程接口所指定的远程方法的代码。这个类也可以含有附加的方法,但客户只能使用远程接口中的方法。因为客户是指向接口的一个句柄,而不是它的哪个类。必须为远程对象定义构造函数,即使只准备定义一个默认构造函数,用它调用基础类构造函数。因为基础类构造函数可能会抛出 java.rmi.RemoteException,所以即使别无它用必须抛出java.rmi.RemoteException例外。 
   以下是远程对象实现类的声明:
java 代码

  1. package com.robin.demo.rmi.impl;   
  2.   
  3. import java.rmi.RemoteException;   
  4. import java.rmi.server.UnicastRemoteObject;   
  5.   
  6. import com.robin.demo.rmi.interf.RmiSample;   
  7.   
  8.   
  9. public class RmiSampleImpl extends UnicastRemoteObject implements RmiSample {   
  10.     /**  
  11.      *   
  12.      */  
  13.     private static final long serialVersionUID = 2742977636753958461L;   
  14.   
  15.     public RmiSampleImpl() throws RemoteException {   
  16.         super();   
  17.     }   
  18.   
  19.     public int sum(int a, int b) throws RemoteException {   
  20.         return a + b;   
  21.     }   
  22.   
  23. }   

   
   三、编写服务器类: 
   包含 main 方法的类可以是实现类自身,也可以完全是另一个类。下面通过RmiSampleServer 来创建一个远程对象的实例,并通过java.rmi.registry.LocateRegistry类的createRegistry 方法从指定端口号启动注册服务程序,也可以通过执行 rmiregistry 命令启动注册服务程序,注册服务程序的缺省运行端口为 1099。必须将远程对象名字绑定到对远程对象的引用上: Naming.rebind("//localhost:8808/SAMPLE-SERVER" , Server); 
   以下是服务器类的声明:
java 代码
  1. package com.robin.demo.rmi.server;   
  2.   
  3. import java.net.MalformedURLException;   
  4. import java.rmi.Naming;   
  5. import java.rmi.RemoteException;   
  6. import java.rmi.registry.LocateRegistry;   
  7.   
  8. import com.robin.demo.rmi.impl.RmiSampleImpl;   
  9.   
  10.   
  11. public class RmiSampleServer {   
  12.   
  13.     /**  
  14.      * @param args  
  15.      */  
  16.     public static void main(String[] args) {   
  17.         try{   
  18.             LocateRegistry.createRegistry(8808);   
  19.             RmiSampleImpl server= new RmiSampleImpl();   
  20.             Naming.rebind("//localhost:8808/SAMPLE-SERVER" , server);   
  21.         }catch (MalformedURLException me){   
  22.             System.out.println("Malformed URL: " + me.toString());   
  23.         }catch(RemoteException re){   
  24.             System.out.println("Remote Exception: "+re.toString());   
  25.         }   
  26.     }   
  27.   
  28. }   

   
   四、编写使用远程服务的客户机类:
   客户机类的主要功能有两个,一是通过Naming.lookup方法来构造注册服务程序 stub 程序实例,二是调用服务器远程对象上的远程方法。 
   以下是服务器类的声明:
java 代码
  1. package com.robin.demo.rmi.client;   
  2.   
  3. import java.rmi.Naming;   
  4. import java.rmi.RemoteException;   
  5.   
  6. import com.robin.demo.rmi.interf.RmiSample;   
  7.   
  8.   
  9. public class RmiSampleClient {   
  10.   
  11.     /**  
  12.      * @param args  
  13.      */  
  14.     public static void main(String[] args) {   
  15.         try {   
  16.             String url = "//localhost:8808/SAMPLE-SERVER";   
  17.             RmiSample RmiObject = (RmiSample) Naming.lookup(url);   
  18.             System.out.println(" 1 + 2 = " + RmiObject.sum(12));   
  19.         } catch (RemoteException rex) {   
  20.             System.out.println("Error in lookup: " + rex.toString());   
  21.         } catch (java.net.MalformedURLException me) {   
  22.             System.out.println("Malformed URL: " + me.toString());   
  23.         } catch (java.rmi.NotBoundException ne) {   
  24.             System.out.println("NotBound: " + ne.toString());   
  25.         }   
  26.   
  27.     }   
  28.   
  29. }   

 
   五、编译代码:
   要编译 Java 源文件,请运行 javac 命令:
   javac RmiSample.java RmiSampleImpl.java RmiSampleServer.java RmiSampleClient.java 
   
   六、为远程对象实现创建根和干: 
   要创建存根程序和骨架文件,应以包含远程对象实现的已编译类包全名运行 rmic 编译器。 
   存根(Stub)是远程对象在客户端的代理,它将RMI调用传递给服务器端的骨架(Skeleton),后者负责将该调用传递给实际的远程方法输入如下: 
   D:\RMI>rmic -d D:\RMI RmiSampleImpl 执行这个命令, 若rmic成功运行,RMI目录下就会多出两个新类: RmiSampleImpl_Stub.class RmiSampleImpl_Skel.class 它们分别对应的是存根(stub)和骨架(skeleton). 
   
   七、运行代码:
   运行服务端程序:在Windows下,输入下列命令,在后台启动RmiSampleServer程序:
   D:\RMI>java RmiSampleServer 
   运行客户端程序: 
   D:\RMI>java RmiSampleClient 
   客户端输出: 1 + 2 = 3 


转载自:

【1】RMI学习笔记

http://blog.csdn.net/fengbenming/article/details/5795369

【2】Java远程方法调用

http://www.congci.com/item/java-rmi-dev-info

原创粉丝点击