------- android培训、java培训、期待与您交流! ----------
RMI
RMI概述
RMI介绍
RMI是Java的一组拥护开发分布式应用程序的API。RMI使用Java语言接口定义了远程对象,它集合了Java序列化和Java远程方法协议(Java Remote Method Protocol)。简单地说,这样使原先的程序在同一操作系统的方法调用,变成了不同操作系统之间程序的方法调用。
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系统运行机理
RMI应用程序通常包括两个独立的程序:服务器程序和客户机程序。典型的服务器应用程序将创建多个远程对象,使这些远程对象能够被引用,然后等待客户机调用这些远程对象的方法。而典型的客户机程序则从服务器中得到一个或多个远程对象的引用,然后调用远程对象的方法。RMI为服务器和客户机进行通信和信息传递提供了一种机制。
在与远程对象的通信过程中,RMI使用标准机制:stub和skeleton。远程对象的stub担当远程对象的客户本地代表或代理人角色。调用程序将调用本地stub的方法,而本地stub将负责执行对远程对象的方法调用。在RMI中,远程对象的stub与该远程对象所实现的远程接口集相同。调用stub的方法时将执行下列操作:初始化与包含远程对象的远程虚拟机的连接;对远程虚拟机的参数进行编组(写入并传输);等待方法调用结果;解编(读取)返回值或返回的异常;将值返回给调用程序。
为了向调用程序展示比较简单的调用机制,stub将参数的序列化和网络级通信等细节隐藏了起来。在远程虚拟机中,每个远程对象都可以有相应的skeleton(在JDK1.2环境中无需使用skeleton)。Skeleton负责将调用分配给实际的远程对象实现。它在接收方法调用时执行下列操作:解编(读取)远程方法的参数;调用实际远程对象实现上的方法;将结果(返回值或异常)编组(写入并传输)给调用程序。stub和skeleton由rmic编译器生成。
RMI例子
远程代理可以作为另一个JVM上对象的本地代表
远程方法调用过程:
客户对象以为客户辅助对象就是真正的服务,客户调用客户辅助对象的doBigThing方法,客户辅助对象打包调用信息(变量,方法名等),通过网络将它运送给服务辅助对象,服务辅助对象把信息解包,调用真正服务对象的doBigThing方法,服务对象将结果返回给服务辅助对象,再通过网络返回给客户辅助对象,最后返回给客户对象,注意调用过程可能发生网络I/O异常
制作远程服务(让普通对象能接收客户的远程调用):
Step1:制作远程接口:定义供客户远程调用的方法
远程接口MyRemote提供客户调用的远程方法sayHello,必须继承Remote,同时方法声明抛出RemoteException异常,确定变量和返回值(String)都是基本数据类型或可序列化(Serializable)
Step2:制作远程实现:真正服务对象,实现远程接口中定义的方法
MyRemoteImpl需要扩展UnicastRemoteObject,实现MyRemote接口,因为UnicastRemoteObject构造器会抛出异常,那么声明MyRemoteImpl构造器抛出异常,实现完MyRemoteImpl后,用RMI Registry注册此服务,这样才能被远程客户调用,注册服务使用到Naming.rebind方法,其实注册到registry中的是Stub(客户辅助对象),因为这才是客户真正需要的
问题:为什么需要继承UnicastRemoteObject?
JDK解释:Used for exporting a remote object with JRMP and obtaining a stub that communicates to the remote object(就是用来获取stub)
Step3:利用rmic产生Stub和Skeleton,就是客户辅助对象和服务辅助对象
在rmi.MyRemoteImpl所在目录(注意是类全称所在的目录)运行rmic(JDK内工具),用来产生MyRemoteImpl_Stub.class和MyRemoteImpl_Skel.class(JDK1.5只产生stub),如:
Step4:启动RMI registry(rmiregistry),将服务注册到registry,实际上是将Stub注册到registry上,注意要在rmi.MyRemoteImpl.class的目录下
Step5:开始远程服务,从服务实现类(MyRemoteImpl)的main方法或者某个独立运行类启动服务:
到此,一个远程服务建立完毕,等待客户的远程调用(通过.bat文件启动服务?)
客户取得Stub对象(代理对象),并调用远程接口方法:
客户到RMI registry中寻找某个名字的Stub(就是Proxy),再调用Stub的方法,客户总是通过远程接口MyRemote作为服务类型,说明返回的Stub实现了MyRemote接口
虽然客户需要Stub类,但是从来不在代码中引用Stub类,客户总是使用远程接口,就如同远程接口就是真正的远程服务对象
RMI中几点注意事项:
1)启动远程服务前先启动rmiregistry,否则服务对象(实际是Stub)注册registry失败
2)远程接口调用方法的变量和返回值必须为基本数据类型或可序列化