JDK5新版RMI编程指南

                                                         JDK5新版RMI编程指南
 
                                         
前言
我前一段时间需要为我的一个Java程序提供远程访问接口,供其他Java程序使用。Java程序可以使用很多种远程访问技术实现这一需求。由于我的远程客户端是java程序,因此,我决定使用RMI这种远程访问技术。RMI是java平台上最快的远程访问技术。
Spring框架为包括RMI在内的各种远程访问技术提供了很好的工具类,能够使我们方便的公布RMI接口和访问RMI远程对象。
但是,我的那个Java程序并没有使用Spring框架。
因此,我研究了怎样在一般的java程序中使用RMI技术。
我寻找了一些RMI资料。根据那些RMI资料,构建一个RMI服务器需要写大量的代码。这太离谱了!一个小小的需求,竟然需要这么大的精力。
后来,我看了javadoc,才发现网上的那些RMI资料都已经过时了。JDK5中,RMI技术已经得到了重大更新。现在使用JDK提供的RMI类,可以相当简单的发布RMI服务!
 
正文
RMI简介
    RMI(Remote Method Invocation),远程方法调用,是一种远程调用java方法的技术。是最早开发出来的java远程访问技术,也是EJB等远程访问技术的基础。
过去,使用RMI技术共有6个步骤要走: (1)定义和实现远端接口中的参数 (2) 定义和实现远端接口 (3) 编写服务端代码 (4)编写客户端代码 (5)生成stub和skeltion ,并将stub打包到客户端jar中,将skeltion打包到服务端jar中 (6)启动rmiregistry , 并将服务注册到rmiregistry中,然后运行代码。
这还需要执行一些命令行程序,非常繁杂!这与RMI这样一种简单的技术非常不相称!
好在JDK5中,RMI得到了重大更新。RMI已经成为一种真正轻量级的简单技术!
JDK5中,使用了动态代理技术,实现了动态生成stub和skeltion类,从而省却了相当多的繁琐工作。RMI的创建和发布已经变得非常简单!
 
建立RMI服务器和注册表
1,Registry接口
java.rmi.registry
接口 Registry
所有超级接口:
Remote

--------------------------------------------------------------------------------

public interface Registryextends RemoteRegistry 是简单远程对象注册表的一个远程接口,它提供存储和获取绑定了任意字符串名称的远程对象引用的方法。bind、unbind 和 rebind 方法用于改变注册表中的名称绑定,lookup 和 list 方法用于查询当前的名称绑定。
 
Registry接口,是RMI对象的注册表,客户端通过这个注册表查询和得到RMI对象。
 
2,LocateRegistry类
java.rmi.registry
类 LocateRegistry
java.lang.Object 
 java.rmi.registry.LocateRegistry
--------------------------------------------------------------------------------

public final class LocateRegistryextends ObjectLocateRegistry 用于获得对特定主机(包括本地主机)上引导远程对象注册表的引用,或用于创建一个接受对特定端口调用的远程对象注册表。
 
   
static Registry createRegistry(int port)
          创建并导出接受指定 port 请求的本地主机上的 Registry 实例。

   
LocateRegistry类的createRegistry()方法,创建并得到对远程RMI对象注册表的引用。
 
    现在,我们就成功创建了一个RMI服务器和对象注册表。
然后,通过调用Registry接口的方法:
void rebind(String name, Remote obj)
          用提供的远程引用替换此注册表中指定的 name 绑定。

我们能够把RMI对象发布到RMI服务器上,并存放到注册表中,能够被RMI客户端发现并访问。
至此,RMI服务器就建立好了!
 
 
编写RMI对象
    Registry接口的方法:
void rebind(String name, Remote obj)
          用提供的远程引用替换此注册表中指定的 name 绑定。

这表明,RMI对象必须是实现了Remote接口的对象。实际上,任何java上的可远程访问对象都需要实现Remote接口!
但是,仅仅实现了Remote接口的对象还不能作为RMI对象被发布。
 
UnicastRemoteObject类
java.rmi.server
类 UnicastRemoteObject
java.lang.Object java.rmi.server.RemoteObject      java.rmi.server.RemoteServer          java.rmi.server.UnicastRemoteObject所有已实现的接口:
Serializable, Remote
直接已知子类:
ActivationGroup

--------------------------------------------------------------------------------

public class UnicastRemoteObjectextends RemoteServer用于导出带 JRMP 的远程对象和获得与该远程对象通信的 stub。
对于下面的构造方法和静态 exportObject 方法,正在导出的远程对象的 stub 按以下方式获得:
如果使用 UnicastRemoteObject.exportObject(Remote)方法导出该远程对象,则加载 stub 类(通常使用 rmic 工具从远程对象的类预生成)并按以下方式构造 stub 类的实例。
“根类”按以下情形确定:如果远程对象的类直接实现扩展 Remote的接口,则远程对象的类为根类;否则,根类为直接实现扩展 Remote 接口的远程对象类的最具派生能力的超类。
要加载的 stub 类的名称通过连接带有后缀 "_Stub" 的根类的二进制名称确定。
按使用根类的类加载器的名称加载 stub 类。该 stub 类必须扩展 RemoteStub并且必须有公共构造方法,该构造方法有一个属于类型 RemoteRef的参数。
o                                            最后,用 RemoteRef构造 stub 类的实例。
 
 
使用UnicastRemoteObject类的方法:
static Remote exportObject(Remote obj, int port)
          使用提供的特定端口导出远程对象,以便能够接收传入的调用。

可以把实现了Remote接口的类生成为RMI对象。可以发布到RMI注册表上!
 
 
生成RMI类的存根类
使用UnicastRemoteObject类的方法:
static Remote exportObject(Remote obj, int port)
          使用提供的特定端口导出远程对象,以便能够接收传入的调用。

使用这个方法返回的Remote对象,可以被发布到RMI的注册表上。使用动态代理,它能够自动生成stub类。这样,只要使用UnicastRemoteObject.exportObject(Remote obj, int port)方法创建RMI注册表上的RMI对象,就不需要我们再关心stub和skeltion类的生成问题。
注意,
static RemoteStub exportObject(Remote obj)
          使用匿名端口导出远程对象,以便能够接收传入的调用。

    这个方法创建的RMI对象,客户端不能自动生成stub类!请不要使用这个方法。
 
    请注意,
static Remote exportObject(Remote obj, int port)
          使用提供的特定端口导出远程对象,以便能够接收传入的调用。

我们使用这个方法时,应该使用0作为第二个参数的值。否则可能会出错!
 
 
RMI最佳实践
看了上面的文字,是不是觉得还是有些复杂呢?接下来,我们看看实际怎样编写RMI程序,你将发现RMI编程确实是非常非常简单!
 
实现Remote接口
RMI发布的类,必须实现Remote接口。我们可以让我们的RMI类实现的接口extend Remote接口。
这就是Remote接口。
public interface Remote {}
可以看到,它实际上是空的,什么都没有。它仅仅是一个标记,表示Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在“远程接口”(扩展 java.rmi.Remote 的接口)中指定的这些方法才可远程使用。
这种标记接口,现在实际上可以用“标注”来达到同样的目的。当初标注没有引入Java中,因此就有了这样的空接口!
 
另外,所有能够远程访问的方法,都必须抛出RemoteException。这是因为,远程调用可能会碰到一些如网络中断这样的错误。
 
可发布为RMI的类
可发布为RMI的类,它必须有参数为空的构造器,构造器必须声明为可抛出RemoteException。
建议构造其中这样写:
UnicastRemoteObject.exportObject(this, 0);
也就是说,构造器构造的是一个可以动态生成存根的RMI对象。
 
当然,你也可以不这么写,但是那样的话就要在注册RMI对象时多写一些代码了!
 
另外,所有远程调用方法的参数,必须实现Serializable接口。
 
发布RMI对象
下面是我的发布RMI对象的代码:
//这是RMI服务器使用的端口,我使用了配置文件
String rMIPort = Config.getInstance().get("RMIPort");
//这样就在指定的端口创建并启动了RMI服务器。否则,你需要在命令行中输入:
//start rmiregistry
//手工启动RMI服务器
              Registry registry = LocateRegistry.createRegistry(new Integer(rMIPort)
                            .intValue());
//我在配置文件中配置了一些RMI类,每一个包括注册表的名字和RMI类的全名
                     Map<String, String> rmis = Config.getInstance().getRmis();
              Set<Map.Entry<String, String>> entrys = rmis.entrySet();
//用叠代器全部拿到,然后一个个放到RMI注册表中,公布出来!
              Iterator it = entrys.iterator();
              while (it.hasNext()) {
                     Map.Entry<String, String> tmp = (Map.Entry<String, String>) it
                                   .next();
                     try {
//创建RMI对象,可以动态生成存根
                            Remote stub = (Remote) Class.forName(tmp.getValue())
                                          .newInstance();
//以指定的名字发布RMI对象到注册表
                            registry.rebind(tmp.getKey(), stub);
                     } catch (InstantiationException e) {
                            /*
                             */
 
                            e.printStackTrace();
                     } catch (IllegalAccessException e) {
                            /*
                             */
 
                            e.printStackTrace();
                     } catch (ClassNotFoundException e) {
                            /*
                             */
 
                            e.printStackTrace();
                     } catch (RemoteException e) {
                            /*
                             */
 
                            e.printStackTrace();
                     }
 
              }
 
访问RMI对象的客户端
    访问RMI对象的客户端也是非常非常简单的。
如:
//RMI服务器的IP地址
String rMIHost=Config.getInstance().get("RMIHost");
//RMI服务器的端口
String rMIPort=Config.getInstance().get("RMIPort");
//得到RMI服务器注册表的引用
            Registry registry = LocateRegistry.getRegistry(rMIHost,new Integer(rMIPort).intValue());
//查找并得到RMI对象的实例。
            IServerREQTerminalConfigService stub = (IServerREQTerminalConfigService) registry.lookup("ServerREQTerminalConfigService");
         //调用远程RMI服务器上的对象的方法!
            stub.rmiRemote();
        
 
就这么简单!
 
结语
在JDK5发布之前,使用RMI是一件非常繁琐的事情。甚至很多程序员把EJB当作对RMI的封装,当作RMI的简化版!
而今,RMI已经得到了巨大的改进。作为Java平台上性能最好远程访问技术,如今也是最简单的远程访问技术,RMI理应得到更广泛的应用。
 
 


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/shendl/archive/2007/08/02/1722441.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值