为通过网络执行其他机器上的代码,传统的方法不仅难以学习,而且易出错。解决这个问题的最佳方法是:某些对象正好位于另一台机器,我们可以发送一条消息,并获得返回结果,就像位于自己的本机器一样。Java远程方法调用(RMI)特性使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。
下面介绍一下必要的步骤,创建自己的RMI对象。
RMI对接口有着强烈的依赖。在需要创建一个远程对象的时候,我们通过传递一个接口来隐藏基层的实施细节。所以客户得到远程对象的一个句柄正好同一些本地的根代码连接,有后者负责通过网络通信。但我们并不关心这些事情,通过自己的接口句柄发送消息即可。
创建一个远程接口时,必须遵守下列规则:
1) 远程接口必须为public属性(不能有“包访问”;也就是说,他不能是“友好的”)。否则,一旦客户试图装载一个实现了远程接口的远程对象,就会得到一个错误。
2) 远程接口必须扩展接口java.rmi.Remote。
3) 除与应用程序本身有关的违例,远程接口中的每个方法都必须在自己的throws从句中声明java.rmi.RemoteException.
4) 作为参数或返回值传递的一个远程对象(不管是直接,还是本地对象中嵌入)必须声明为远程接口,不可声明为实施类。
下面是一个远程接口示例,
//PerfectTimeI.java<o:p> </o:p>
//The PerfectTime remote interface<o:p> </o:p>
package test;<o:p> </o:p>
import java.rmi.*;<o:p> </o:p>
public interface PerfectTimeI extends Remote {<o:p> </o:p>
long getPerfectTime() throws RemoteException;<o:p> </o:p>
}<o:p> </o:p>
它表面上与其他的接口类似,只是对Remote进行了扩展,而且所有的方法都会“掷”出RemoteException.接口和方法都是Public的。<o:p> </o:p>
编译PerfectTimeI.java,生成PerfectTimeI.class(test是包,编译时注意路径)
G:\RMI>javac test\PerfectTimeI.java<o:p> </o:p>
服务器必须包含一个扩展了UnicastRemoteObject类,并实现远程接口。这个类也可以含有附加的方法,但客户只能使用远程接口中的方法。因为客户是指向接口的一个句柄,而不是它的哪个类。
必须为远程对象定义构件器,即使只准备定义一个默认构件器,用它调用基础类构件器。必须把它明确地编写出来,因为它必须“掷”出RemoteException违例。
下面列出远程接口PerfectTime的事实过程:他代表精确计时服务
//PerfectTime.java<o:p> </o:p>
//The implementation of the PerfectTime remote object<o:p> </o:p>
package test;<o:p> </o:p>
import java.net.*;<o:p> </o:p>
import java.rmi.*;<o:p> </o:p>
import java.rmi.registry.*;<o:p> </o:p>
import java.rmi.server.*;<o:p> </o:p>
public class PerfectTime extends UnicastRemoteObject implements PerfectTimeI <o:p></o:p>
{<o:p> </o:p>
//默认构件器,也要“掷”出RemoteException违例。<o:p> </o:p>
public PerfectTime() throws RemoteException {<o:p> </o:p>
super();<o:p> </o:p>
}<o:p> </o:p>
public long getPerfectTime() throws RemoteException {<o:p> </o:p>
return System.currentTimeMillis();<o:p> </o:p>
}<o:p> </o:p>
public static void main(String[] args) {<o:p> </o:p>
/*创建和安装一个安全管理器,令其支持RMI.作为Java开发包的一部分,适用于RMI唯一一个是RMISecurityManager.*/<o:p> </o:p>
System.setSecurityManager(new RMISecurityManager());<o:p> </o:p>
try {<o:p> </o:p>
/*创建远程对象的一个或多个实例,下面是PerfectTime对象*/<o:p> </o:p>
PerfectTime pt = new PerfectTime();<o:p> </o:p>
/*向RMI远程对象注册表注册至少一个远程对象。一个远程对象拥有的方法即可生成指向其他远程对象的句柄,这样,客户到注册表里访问一次,得到第一个远程对象即可.*/<o:p> </o:p>
Naming.bind("PerfectTime", pt);<o:p> </o:p>
System.out.println("Ready to do Time");<o:p> </o:p>
} catch (Exception e) {<o:p> </o:p>
e.printStackTrace();<o:p> </o:p>
}<o:p> </o:p>
}<o:p> </o:p>
}<o:p> </o:p>
编译PerfectTime.java,生成PerfectTime.class(test是包,编译时注意路径)
G:\RMI>javac test\PerfectTime.java<o:p> </o:p>
创建RemoteObject的主干和框架。要完成这个工作可使用rmic编译器,rmic编译器生成远程对象的存根和骨架。存根(Stub)是远程对象在客户端的代理,它将RMI调用传递给服务器端的骨架(Skeleton),后者负责将该调用传递给实际的远程方法输入如下:
G:\RMI>rmic -d G:\RMI test.PerfectTime
执行这个命令,
若rmic成功运行,test目录里就会多出两个新类:
PerfectTime_Stub.class<o:p> </o:p>
PerfectTime_Skel.class<o:p> </o:p>
它们分别对应的是根(stub)和干(skeleton).
RMI全部的宗旨就是可能简化远程接口对象的使用。我们客户程序中要做的唯一一件额外事情是查找从服务器取回远程接口。下面就是编写的Java程序:将消息发给对象:
//DisplayPerfectTime.java<o:p> </o:p>
//Users remote object PerfectTime<o:p> </o:p>
package test;<o:p> </o:p>
import java.rmi.*;<o:p> </o:p>
import java.rmi.registry.*;<o:p> </o:p>
public class DisplayPerfectTime {<o:p> </o:p>
/*** DisplayPerfectTime 构造子注解。*/<o:p> </o:p>
public DisplayPerfectTime() {<o:p> </o:p>
super();<o:p> </o:p>
}<o:p> </o:p>
public static void main(String[] args) {<o:p> </o:p>
System.setSecurityManager(new RMISecurityManager());<o:p> </o:p>
try {<o:p> </o:p>
PerfectTimeI t = (PerfectTimeI) Naming.lookup("PerfectTime");<o:p> </o:p>
for (int i = 0; i < 10; i++) {<o:p> </o:p>
System.out.println("PerfectTime:" + t.getPerfectTime());<o:p> </o:p>
}<o:p> </o:p>
} catch (Exception e) {<o:p> </o:p>
e.printStackTrace();<o:p> </o:p>
}<o:p> </o:p>
}
}<o:p> </o:p>
编译DisplayPerfectTime.java.
G:\RMI>javac test\DisplayPerfectTime.java<o:p> </o:p>
在运行PerfectTime类和DisplayPectTime类之前,用户必须首先在将要宿主PerfectTime的计算机上启动RMI注册(Registry)程序,即使将要运行PerfectTime的计算机与运行DisplayPerfectTime的是同一台机器,这一步也是必须的。注册表服务器的名字是rmiregistry.在32位Windows环境中,可使用: start rmiregistry 令其在后台运行。然后分别开两个不同的进程运行Server端和Client端:启动注册表服务器:
G:\RMI>start rmiregistry<o:p> </o:p>
绑定PerfectTime到注册,运行服务端程序:在Windows下,输入下列命令,在后台启动PerfectTime程序:
G:\RMI>java test.PerfectTime<o:p> </o:p>
Ready to do Time<o:p> </o:p>
运行客户端程序:如下
G:\RMI>java test.DisplayPerfectTime<o:p> </o:p>
PerfectTime:961722589649<o:p> </o:p>
PerfectTime:961722589669<o:p> </o:p>
PerfectTime:961722589679<o:p> </o:p>
PerfectTime:961722589679<o:p> </o:p>
PerfectTime:961722589689<o:p> </o:p>
PerfectTime:961722589689<o:p> </o:p>
PerfectTime:961722589689<o:p> </o:p>
PerfectTime:961722589699<o:p> </o:p>
PerfectTime:961722589699<o:p> </o:p>
PerfectTime:961722589699<o:p> </o:p>