1、定义
Java远程方法调用 ,即Java RMI (Java Remote Method Invocation)是Java编程语言里,一种用于 实现远程过程调用 的应用程序编程接口 。它使客户机上运行的程序可以调用远程服务器上 的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。
Java RMI极大地依赖于接口。在需要创建一个远程对象的时候,程序员通过传递一个接口来隐藏底层的实现细节。客户端得到的远程对象句柄正好与本地的根代码连 接,由后者负责透过网络通信。这样一来,程序员只需关心如何通过自己的接口句柄发送消息。
接口的两种常见实现方式是:最初使用JRMP (Java Remote Message Protocol,Java远程消息交换协议)实现;此外还可以用与CORBA兼容的方法实 现。RMI 一般指的是编程接口,也有时候同时包括JRMP和API(应用程序编程接口 ),而RMI-IIOP 则一般指RMI接口接管绝大部分的功能,以支持CORBA的实现。
最初的RMI API设计为通用地支持不同形式的接口实现。后来,CORBA增加了传值(pass by value)功能,以实现RMI接口。然而RMI-IIOP 和JRMP 实现的接口并不完全一致。
所使用Java包的名字是java.rmi
。
2、例子
创建RMI程序的6个步骤:
1、定义一个远程接口的接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常。
2、定义一个实现该接口的类。
3、使用RMIC程序生成远程实现所需的残根和框架。
4、创建一个服务器,用于发布2中写好的类。
5. 创建一个客户程序进行RMI调用。
6、启动rmiRegistry并运行自己的远程服务器和客户程序
一、定义一个远程接口的接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常
package rmi; import java.rmi.RemoteException; /** * 第一步,定义一个远程接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常 */ //接口里定义一个返回字符串的远程方法 SayHello(),这个远程接口 I_Hello必须是public的 //它必须从java.rmi.Remote继承而来,接口中的每一个方法都必须抛出远程异常java.rmi.RemoteException。 // //抛出这个异常的原因:由于任何远程方法调用实际上要进行许多低级网络操作,因此网络错误可能在调用过程中随时发生 //因此,所有的RMI操作都应放到try-catch块中 //需要从Remote继承 public interface I_Hello extends java.rmi.Remote{ //需要抛出remote异常 public String SayHello() throws RemoteException; }
二、定义一个实现该接口的类
package rmi; import java.rmi.*; import java.rmi.server.UnicastRemoteObject; /** * 第二步,定义一个实现远程接口的类 */ //实现接口的类必须继承UnicastRemoteObject类,扩展java.rmi.server.UnicastRemoteObject public class Hello extends UnicastRemoteObject //必须从UnicastRemoteObject 继承 implements I_Hello { public Hello() throws RemoteException{ //需要一个抛出Remote异常的默认初始化方法 } public String SayHello(){ //这个是实现I_Hello接口的方法 return "Hello world !!"; } }
三、使用RMIC程序生成远程实现所需的残根Stub 和 框架
这一步是关键,也是最容易出问题的地方,需要多说几句:
在RMI中,客户机上生成的调动调用参数和反调动返回值的代码称为残根。有的书上称这部分代码为“主干”。
服务器上生成的反调动调用参数和进行实际方法调用调动返回值的代码称为框架
二中的Hello编译好以后,我们就可以用RMIC命令来生成残根Stub
操作是:在cmd下到Hello.class 所在目录,运行以下命令:rmic Hello
命令执行完以后,将会在当前目录生成一个 Hello_Stub.class 这个就是我们远程调用时需要的类
四、创建一个服务器,用于发布2中写好的类
package rmi; import java.rmi.*; /** * 4步,创建一个服务器,用于发布类Hello */ public class RMI_Server { public static void main(String[] args) { try { //实例化要发布的类 Hello hello = new Hello(); //绑定RMI名称 进行发布,即客户端通过这个名字查找的对象就是hello这个实例 Naming.rebind("RMI_Hello", hello); System.out.println("=== Hello server Ready === "); } catch (Exception exception) { exception.printStackTrace(); } } }
五、创建一个客户程序进行RMI调用
package rmi; /** * 5步,创建一个客户程序进行RMI调用 */ import java.rmi.*; public class RMI_Client { public static void main(String[] args) { try { I_Hello hello = (I_Hello) Naming.lookup("RMI_Hello"); //通过RMI名称查找远程对象 //如果是异地的RMI调用请参照 rmi://127.0.0.1:1099/RMI_Hello //端口1099是默认的RMI端口,如果你启动 rmiregistry 的时候,没有指定特殊的端口号,默认就是1099 System.out.println(hello.SayHello()); //核心句:调用远程对象的方法 } catch (Exception e) { e.printStackTrace(); } } }
六、启动rmiRegistry并运行自己的远程服务器和客户程序
cmd下运行命令rmiregistry,然后放在一边不用管他
然后通过cmd运行Server,直接在IDE里运行一般会报错:找不到Stub类,需要用下面的命令来运行,命令里指定了stub类的路径
cmd到D:\workspace_bohai_FXM\ztest>目录下运行java.exe -Djava.rmi.server.codebase=file:/D:\workspace_bohai_FXM\ztest/ rmi.RMI_Server
(注意:ztext是项目名,rmi是包,最后的那个ztest/后有一个空格)
回车后cmd会显示:=== Hello server Ready ===
(代表Server成功启动,第二个cmd窗口)
然后在运行Client就会看到你千辛万苦远程方法调用的结果:Hello world !!