http://www.blogjava.net/yruc/archive/2007/01/11/93215.html
l 在 RMI 的基本架构之上, RMI 提供服务与分布式应用程序的一些对象服务,包括对象的命名 / 注册( Naming/Registry )服务,远程对象激活( Activation )服务以及分布式垃圾收集( Distributed Garbage Collection, DGC )。
l 在前一节中,如果你喜欢刨根问底,可能已经注意到,客户端要调用远程对象,是通过其代理对象 Stub 完成的,那么 Stub 最早是从哪里得来的呢? RMI 的命名 / 注册服务正是解决这一问题的。当服务器端想向客户端提供基于 RMI 的服务时,它需要将一个或多个远程对象注册到本地的 RMI 注册表中(参见 java.rmi.registry.Registry API )。每个对象在注册时都被指定一个将来用于客户程序引用该对象的名称。客户程序通过命名服务(参见 java.rmi.Naming API ),指定类似 URL 的对象名称就可以获得指向远程对象的远程引用。在 Naming 中的 lookup() 方法找到远程对象所在的主机后,它将检索该主机上的 RMI 注册表,并请求所需的远程对象。如果注册表发现被请求的远程对象,它将生成一个对该远程对象的远程引用,并将其返回给客户端,客户端则基于远程引用生成相应的 Stub 对象,并将引用传递给调用者。之后,双方就可以按照我们前面讲过的方式进行交互了。
package test;
import java.rmi.Remote;
import java.rmi.RemoteException;
//我们的远程接口定义。该接口只有一个方法:executeTask() 用以执行指定的计算任务,并返回相应的结果。
//注意,我们用后缀 Remote 表明接口是远程接口。
public interface ComputerEngineRemote extends Remote {
public Object excuteTask(Task task) throws RemoteException;
}
*******************************************************************************************************************************************************
package test;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/* UnicastRemoteObject 类是一个便捷类,它实现了我们前面所讲的基于 TCP/IP 的点对点通讯机制。
远程对象都必须从该类扩展(除非你想自己实现几乎所有 UnicastRemoteObject 的方法)。
在我们的实现类的构造函数中,调用了超类的构造函数(当然,即使你不显式的调用这个构建函数,它也一样会被调用。
这里这样做,只是为了突出强调这种调用而已)。该构造函数的最重要的意义就是调用 UnicastRemoteObject 类的
exportObject() 方法。导出(Export)对象是指使远程对象准备就绪,可以接受进来的调用的过程。
而这个过程的最重要内容就是建立服务器套接字,监听特定的端口,等待客户端的调用请求。*/
public class ComputerEngine extends UnicastRemoteObject implements
ComputerEngineRemote {
protected ComputerEngine() throws RemoteException {
super();
}
public Object excuteTask(Task task) throws RemoteException {
return task.excute();
}
}
*******************************************************************************************************************************************************
package test;
import java.io.Serializable;
/*业务接口
execute() 用以执行实际的计算逻辑,并返回结果。
注意,该接口不是远程接口,所以没有扩展 java.rmi.Remote 接口;其方法也不必抛出 java.rmi.RemoteException 异常。
但是,因为它将用作远程方法的参数,所以扩展了 java.io.Serializable 接口。*/
public interface Task extends Serializable {
Object excute();
}
*******************************************************************************************************************************************************
package test;
public class TaskImpl implements Task {
public Object excute() {
return "Hello World!!!";
}
}
*******************************************************************************************************************************************************
package test;
import java.rmi.Naming;
public class Bootstrap {
/* 为了让客户程序可以找到我们的远程对象,就需要将我们的远程对象注册到 RMI 的注册表。
这个过程有时被称为"引导"过程(Bootstrap)。我们将为此编写一个独立的引导程序负责创建和注册远程对象。*/
public static void main(String[] args) throws Exception {
String name="ComputerEngine";
ComputerEngine engine=new ComputerEngine();
System.out.println("ComputerEngine exported");
//将指定名称绑定到一个远程对象
Naming.rebind(name, engine);
System.out.println("ComputerEngine bound");
}
}
/*编译示例程序
为远程对象实现创建根和干:
要创建存根程序和骨架文件,应以包含远程对象实现的已编译类包全名运行 rmic 编译器。
存根(Stub)是远程对象在客户端的代理,它将RMI调用传递给服务器端的骨架(Skeleton),后者负责将该调用传递给实际的远程方法输入如下:
E:>rmic -d D:\RMI ComputerEngine (远程接口实现类)执行这个命令, 若rmic成功运行,RMI目录下就会多出两个新类: RmiSampleImpl_Stub.class RmiSampleImpl_Skel.class 它们分别对应的是存根(stub)和骨架(skeleton).
这里用rmic命令编译生成stud类有一定的技巧,本人就搞了很久才搞出来,老是报找不到类的错误具体解决如下
*先把所有的*.java文件拷贝到e: est目录下,再把它们的包名全部去掉,再执行下面的过程
E:>rmic -classpath E: est ComputerEngine
运行示例程序
远程对象的引用通常是通过 RMI 的注册表服务以及 java.rmi.Naming 接口获得的。远程对象需要导出(注册)相应的远程引用到
注册表服务,之后注册表服务就可以监听并服务于客户端对远程对象引用的请求。标准的 Sun Java SDK 提供了一个简单的 RMI
注册表服务程序,即 rmiregistry 用于监听特定的端口,等待远程对象的注册,以及客户端对这些远程对象引用的检索请求。
在运行我们的示例程序之前,首先要启动 RMI 的注册表服务。这个过程很简单,只要直接运行 rmiregistry 命令即可。缺省的
情况下,该服务将监听 1099 端口。如果需要指定其它的监听端口,可以在命令行指定希望监听的端口(如果你指定了其它端口,
需要修改示例程序以适应环境)。如果希望该程序在后台运行,在 Unix 上可以以如下方式运行(当然,可以缺省端口参数):
$ rmiregistry 1099 &
在 Windows 操作系统中可以这样运行:
E:>start rmiregistry 1099
本人就是直接打的start rmiregistry
我们的 test.Bootstrap 类将用于启动远程对象,并将其绑定在 RMI 注册表中。运行该类后,远程对象也将进入
监听状态,等待来自客户端的方法调用请求。
E: est>java Bootstrap
ComputerEngine exported
ComputerEngine bound
启动远程对象后,打开另一个命令行窗口,运行客户端。命令行的参数为 RMI 注册表的地址,参考下面的示例:
E: est>java rmitutorial
*/
*******************************************************************************************************************************************************
package test;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class Client {
/**
* @param args
* @throws NotBoundException
* @throws RemoteException
* @throws MalformedURLException
*/
public static void main(String[] args) throws Exception {
String name="rmi://localhost/ComputerEngine";
// 即创建Home接口实例,EJB的原理也就是像这个例子一样,部署到JNDI命名目录上的其实是HOME工厂接口,通过Home工厂
// 可以创建远程接口的实例,调用他的方法.
ComputerEngineRemote engineRemote=(ComputerEngineRemote) Naming.lookup(name);
System.out.println(engineRemote.excuteTask(new TaskImpl()));
}
}
深入理解Java RMI分布式对象调用机制
本文详细介绍了Java RMI(Remote Method Invocation)的分布式对象调用原理,包括RMI架构、调用过程、对象服务以及实战案例。通过实例展示了如何定义远程接口、实现类,并注册远程对象到RMI注册表,最终实现远程对象之间的调用。

985

被折叠的 条评论
为什么被折叠?



