Java RMI 使用快速入门

wanmeilingdu 贡献于2012-12-02

作者 王雷锋  创建于2009-12-17 17:29:00   修改者lblong  修改于2010-08-23 02:37:00字数8003

文档摘要:RMI目前使用Java远程消息交 换协议JRMP(Java Remote Messaging Protocol)进行通信。JRMP是专为Java的远程对象制定的协议。因此,Java RMI具有Java的“Write Once,Run Anywhere”的优点,是分布式应用系统的百分之百纯Java解决方案。用Java RMI开发的应用系统可以部署在任何支持JRE(Java Run Environment Java,运行环境)的平台上。但由于JRMP是专为Java对象制定的,因此,RMI对于用非Java语言开发的应用系统的支持不足。不能与用非Java语言书写的对象进行通信。
关键词:

一. RMI原理及介绍 1.基本介绍 RMI目前使用Java远程消息交 换协议JRMP(Java Remote Messaging Protocol)进行通信。JRMP是专为Java的远程对象制定的协议。因此,Java RMI具有Java的“Write Once,Run Anywhere”的优点,是分布式应用系统的百分之百纯Java解决方案。用Java RMI开发的应用系统可以部署在任何支持JRE(Java Run Environment Java,运行环境)的平台上。但由于JRMP是专为Java对象制定的,因此,RMI对于用非Java语言开发的应用系统的支持不足。不能与用非Java语言书写的对象进行通信。 Java Remote Method Invocation ( RMI -- Java远程方法调用)允许您使用Java编写分布式对象。本文将介绍RMI的优点以及如何将其连接到现有的和原有的系统中,以及与用Java 编写的组件的连接。 RMI为采用Java对象的分布式计算提供了简单而直接的途径。这些对象可以是新的Java对象,也可以是围绕现有API的简单的Java包装程序。Java体现了“编写一次就能在任何地方运行的模式。而RMI可将Java模式进行扩展,使之可在任何地方运行”。因为RMI是以Java为核心的,所以,它将Java的安全性和可移植性等强大功能带给了分布式计算。务逻辑等属性移动到网络中最合适的地方。如果您要扩展Java在系统中的使用,RMI将使您充分利用其强大功能。 RMI可利用标准Java本机方法接口JNI与现有的和原有的系统相连接。RMI还可利用标准JDBC包与现有的关系数据库连接。RMI/JNI和RMI/JDBC相结合,可帮助您利用RMI与目前使用非Java语言的现有服务器进行通信,而且在您需要时可扩展Java在这些服务器上的使用。RMI可帮助您在扩展使用时充分利用Java的强大功能。 2.基本组成 一个正常工作的RMI系统由下面几个部分组成: 1)远程服务的接口定义 2)远程服务接口的具体实现 3)桩(Stub)和框架(Skeleton)文件 4)一个运行远程服务的服务器 5)一个RMI命名服务,它允许客户端去发现这个远程服务 6)类文件的提供者(一个HTTP或者FTP服务器) 7)一个需要这个远程服务的客户端程序 3. 原理 RMI系统结构,在客户端和服务器端都有几层结构。 --------- ---------- | 客户 | | 服务器| ---------- ---------- | | ------------- ---------- | 占位程序 | | 骨干------------------ | 远 程 引 用 层 | ------------------------------------ | | ------------------------------------ | 传 输 层 | ------ ------------------------------ 方法调用从客户对象经占位程序(Stub)、远程引用层(Remote Reference Layer)和传输层(Transport Layer)向下,传递给主机, 然后再次经传 输层,向上穿过远程调用层和骨干网(Skeleton),到达服务器对象。 占位程序扮演着远程服务器对象的代理的角色,使该对象可被客户激活。 远程引用层处理语义、管理单一或多重对象的通信,决定调用是应发往一个服务器还是多个。传输层管理实际的连接,并且追追踪可以接受方法调用的远程对象。服 务器端的骨干网完成对服务器对象实际的方法调用,并获取返回值。返回值向下经远程引用层、服务器端的传输层传递回客户端,再向上经传输层和远程调用层返回。最后,占位程序获得返回值。 要完成以上步骤需要有以下几个步骤: 1)生成一个远程接口 2)实现远程对象(服务器端程序) 3)生成占位程序和骨干网(服务器端程序) 4)编写服务器程序 5)编写客户程序 6)注册远程对象 7)启动远程对象 二.RMI在spring环境下使用 1. 首先导入各种spring的jar包(打钩的一定要有的) 2. 编写接口以及实现类 public interface ICalculator { public long add(long a, long b); public long sub(long a, long b); public long mul(long a, long b); public long div(long a, long b); }//参数必须是可序列化的参数实现java.io.Serializable public class CalculatorImp implements ICalculator {} 3. 配置spring文件 服务端: 客户端: 4. 服务端启动会在web服务器启动的时候启动 如果不是web服务器,则需要线程进行启动。 ApplicationContext context = new ClassPathXmlApplicationContext("context/RmiServiceContext.xml"); System.out.println("RMI starting ok....."); 5. 客户端调用 获取服务端bean并强转为相应的接口就可以使用了 ApplicationContext context = new ClassPathXmlApplicationContext("context/RmiStubContext.xml"); ICalculator stub = (ICalculator) context.getBean("someServiceProxy"); stub.add(100,20); 参考资料:http://docs.huihoo.com/spring/zh-cn/remoting.html; http://mhbjava.javaeye.com/blog/26597; 三.不在spring中使用RMI 分为以下四个步骤 1. 创建远程接口及声明远程方法(HelloInterface.java) 2. 实现远程接口及远程方法(继承UnicastRemoteObject)(Hello.java) 3. 启动RMI注册服务,并注册远程对象(HelloServer.java) 4. 客户端查找远程对象,并调用远程方法(HelloClient) 5. 执行程序:启动服务HelloServer;运行客户端HelloClient进行调用 具体代码及对应步骤如下: 1) 创建远程接口及声明远程方法(HelloInterface.java) java 代码 package com.unmi; import java.rmi.*; /** * 远程接口必须扩展接口java.rmi.Remote */ public interface HelloInterface extends Remote { /** * 远程接口方法必须抛出 java.rmi.RemoteException */ public String say() throws RemoteException; } 2) 实现远程接口及远程方法(继承UnicastRemoteObject)Hello.java 如果传递参数,参数必须是可序列化的参数实现java.io.Serializable java 代码 package com.unmi; import java.rmi.*; import java.rmi.server.*; /** * 扩展了UnicastRemoteObject类,并实现远程接口 HelloInterface */ public class Hello extends UnicastRemoteObject implements HelloInterface { private String message; /** * 必须定义构造方法,即使是默认构造方法,也必须把它明确地写出来,因为它必须抛出出RemoteException异常 */ public Hello(String msg) throws RemoteException { message = msg; } /** * 远程接口方法的实现 */ public String say() throws RemoteException { System.out.println("Called by HelloClient"); return message; } } 3) 启动RMI注册服务,并注册远程对象(HelloServer.java) java 代码 package com.unmi; import java.rmi.Naming; import java.rmi.registry.LocateRegistry; public class HelloServer { /** * 启动 RMI 注册服务并进行对象注册 */ public static void main(String[] argv) { try { //启动RMI注册服务,指定端口为1099 (1099为默认端口) //也可以通过命令 $java_home/bin/rmiregistry 1099启动 //这里用这种方式避免了再打开一个DOS窗口 //而且用命令rmiregistry启动注册服务还必须事先用RMIC生成一个stub类为它所用 LocateRegistry.createRegistry(1099); //创建远程对象的一个或多个实例,下面是hello对象 //可以用不同名字注册不同的实例 HelloInterface hello = new Hello("Hello, world!"); //把hello注册到RMI注册服务器上,命名为Hello Naming.rebind("Hello", hello); //如果要把hello实例注册到另一台启动了RMI注册服务的机器上 //Naming.rebind("//192.168.1.105:1099/Hello",hello); System.out.println("Hello Server is ready."); } catch (Exception e) { System.out.println("Hello Server failed: " + e); } } } 4) 客户端查找远程对象,并调用远程方法(HelloClient) java 代码 package com.unmi; import java.rmi.Naming; public class HelloClient { /** * 查找远程对象并调用远程方法 */ public static void main(String[] argv){ try{ HelloInterface hello = (HelloInterface) Naming.lookup("Hello"); //如果要从另一台启动了RMI注册服务的机器上查找hello实例 //HelloInterface hello = (HelloInterface)Naming.lookup("//192.168.1.105:1099/Hello"); //调用远程方法 System.out.println(hello.say()); } catch (Exception e) { System.out.println("HelloClient exception: " + e); } } } 5)执行程序:启动服务HelloServer;运行客户端HelloClient进行调用 代码如何编译这里就不细讲 (1)打开一个Dos窗口执行命令 java com.unmi.HelloServer 启动服务HelloServer E:workspaceTestRMIbin>java com.unmi.HelloServer Hello Server is ready. 运行成功则可以看到 Hello Server is ready (2)打开另一个Dos窗口执行命令 java com.unmi.HelloClient 运行客户端程序 E:workspaceTestRMIbin>java com.unmi.HelloClient Hello, world! 调用成功则可以看到 Hello, world! 并且在启动服务端的窗口中看到紧跟 Hello Server is ready. 打印出 Called by HelloClient 如果您能一路顺畅的执行到这里,恭喜!您已度过了一个轻快的RMI之旅。 最后来个说明: 本实例中并没有用到JDK所带的命令 rmic 编译实现类得到存根(Stub)类,也没用命令 rmiregistry 命令来启动RMI注册服务。在启动 rmiregistry之前必须能让它加载到相应的stub类,这就是造成**_Stub 类找不到的原因。 如果只是按上面的代码,则服务程序 HelloServer 和客户端程序 HelloClient 都必须运行在本机(如此则RMI有何意义呢?);别急,只要修改HelloClient类,使用第二种形式的lookup查找语句,注释第一条 lookup语句,取消注释第二条lookup语句 //HelloInterface hello = (HelloInterface) Naming.lookup("Hello"); //如果要从另一台启动了RMI注册服务的机器上查找hello实例 HelloInterface hello = (HelloInterface)Naming.lookup("//192.168.1.105:1099/Hello"); 其中的IP地址和端口号1099为 RMI 注册服务器的IP和端口号,这样你的HelloClient就可以在另一台机器运行了,当然HelloInterface类必须能找到(但也可指定参数- Djava.rmi.server.codebase从网络加载HelloInterface类)。lookup("Hello")默认为从本机 127.0.0.1的1099端口上查找Hello命令对象,如果第二条语句写成lookup("192.168.1.105/Hello")与原语句是 同等的,因为默认端口号就是1099。 代码中 HelloServer 和 HelloClient 省略了设置安全管理器的过程 System.setSecurityManager(new RMISecurityManager()); ,如果设置的安全管理则必须编写相应的访问策略文件,并且在执行时指定参数 无论是启动服务端还是客户端都可以用参数 java.rmi.server.codebase=http://unmi.blogcn.cn/bin 的形式,像JNP一样从网络上加载类,这样更方便于RMI客户端的部署,如RMI客户端是一个Applet 可以拿单独一台机器运行 rmiregistry (它需要能加载到相应的stub类,设置classpath)或用LocateRegistry.createRegistry(port),只作为 RMI远程对象的RMI集中注册的服务器,真正提供服务对象只往上注册,客户端只需从注册服务器上查找远程对象引用,然后调用远程方法,具体由谁提供服务 由注册服务器来帮助联络。 还可以用 RMI Activation 编程方式来实现RMI远程方法调用,具体请参考 http://java.sun.com/j2se/1.4.2/docs/guide/rmi/activation.html 把HelloServer和HelloClient中的 "//192.168.1.105:1099/Hello 写成 rmi:/192.168.1.105:1099/Hello 感觉会好看一些,因为直接感觉就是在处理rmi协议。 6) 使用插件进行编译启动 1>RMI-eclipse plugin 插件安装 http://www.genady.net/rmi/v20/downloads.html (该插件可试用,不是免费的。。。。。。不过网上有破解版的) 2>服务端代码一样,只是编译使用工具进行生成: 点击项目工程 右键->RMI--Enable Stubs Generation 进行生成代码 如果修改代码后,点击项目工程 右键-show view->others,在弹出菜单中选择RMI Views->RMI Registry Inspector,这是会多出来一个窗口,这里可以显示已经注册的RMI应用。 点击工具条上的RMI Plugin图标,在菜单中选择Start Local Registry。 再运行-->cmd--->cd 进入你项目生成class文件所在目录注意这个只需要启动一次,除非你把它关掉。 (2)配置运行RMI服务 右键点击左边树中的RMI_Server.java文件,菜单Debug As ->RMI Application。在弹出对话框中找到RMI Properties标签页 这时这里前两项显示红色。 选中java.security.police项的value框,点击选择按钮会出现文件选择对话框,我们这里设置成C:\Java \jre1.5.0_05\lib\security\java.security。就是jre的安全策略配置文件,要选择成泥当前用的jdk的侧略文 件。 选中第二项java.rmi.server.codebase的 value项,这里选择编译后类包所在的文件夹。点击选择按钮->add按钮->pick from workspace,选择当前工程的bin文件夹。 点击apply按钮。 点击debug按钮。 (3)单击RmiServer选择Run as--RMI Application (4)单击RmiClient选择Run as--Java Application 参考资料: http://www.hudong.com/wiki/RMI http://damies.javaeye.com/blog/51778 http://hubin.javaeye.com/blog/150492 http://rf.cepark.com/index.php/action-viewnews-itemid-381

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享文档获得金币 ] 2 人已下载

下载文档