RMIAPIJDK1.1 后就已经开始支持,并从 JDK5 之后,在 RMIAPI 开发上进行极大的简化,让开发变得非常容易。但为了让大家更好的了解相关的技术,在本章节中,除了 JDK5RMIAPI 使用说明外,也会介绍之前的 API 开发与实现原理说明。

Java RMIAPI 都在 java.rmi 包下:

  • java.rmi.Remote 所有可以被远程调用的对象都必须实现该接口。
  • java.rmi.server.UnicastRemoteObject 所有可以被远程调用的对象都必须扩展该类。

RMI 体系结构图:


RMI 在桩/框架层利用了两种关键技术。一种是 java 语言志用的对象串行化(Object serialization)技术,该技术支持将对象的类型与值信息转为平坦的字节流形式,并可利用这种串行化表示重建与原对象状态相同的同类型对象,从 而实现对象状态的持久性或网络传输,桩和框架利用这一技术对远程调用的参数与返回值进行打包与解包。另一种技术是动态类装载(Dynamic class loading),用于在程序动态远行时装载客户程序所需的框,并支持 java 语言内建的类型检查与类型转换机制。

  • JDK 1.5 之前版本的开发步骤如下:

    定义接口,继承 java.rmi.Remote

    以简单的 Hello World 为例:

    public interface Greeter extends java.rmi.Remote{
    String hello(String name) throws java.rmi.RemoteException;
    }

    定义实现,继承 UnicastRemoteObject

    public class GreeterImpl extends UnicastRemoteObject implements Greeter {
        /**
         * serialVersionUID
         */
        private static final long serialVersionUID = -5870885426008943753L;
        /**
         * 
         * @throws RemoteException
         */
        public GreeterImpl() throws RemoteException {
            //继承了UnicastRemoteObject,必须实现相应的构造器
            super();
        }
        public String hello(String name) throws RemoteException {
            return "Say hello world to " + name;
        }
    }

    开发服务器端

    public class GreeterServer {
        public static void main(String[] args){
            try {
                GreeterImpl greeterImpl = new GreeterImpl();
                //绑定服务对象
                try {
                    Naming.bind("HelloWorld", greeterImpl);
                } catch (AlreadyBoundException e) {
                    e.printStackTrace();
                }
                System.out.println("系统已经成功绑定服务对象.");
            } catch (RemoteException e) {
                System.out.println("错误信息为:" + e.getMessage());
                e.printStackTrace();
            } catch (MalformedURLException e) {
                System.out.println("错误信息为:" + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    编写客户端

    public class GreeterClient {
        public static void main(String[] args){
            try {
                //如果是其它服务器,则查找 rmi://server_name/HelloWorld
                Greeter greeter = (Greeter)Naming.lookup("rmi://127.0.0.1/HelloWorld ");
                System.out.println(greeter.hello("ZIZZ"));
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (RemoteException e) {
                e.printStackTrace();
            } catch (NotBoundException e) {
                e.printStackTrace();
            }
        }
    }

    使用 rmic 产生客户端桩

    rmic zizz.rmi.GreeterImpl

    使用 rmic 将会产生一个 GreeterImpl_Stub.class 的新文件

    将产生的客户端桩及接口 copy 到客户端

    GreeterImpl_Stub.classGreeter.class 这两个文件,使用 jar 命令打个包,取名叫 rmiclient.jar

    命令如下:

    jar cvf rmiclient.jar zizz/rmi/GreeterImpl_Stub.class zizz/rmi/Greeter.class

    启用服务器端,将服务对象绑定到 rmigegistry 当中

    java zizz.rmi.GreeterServer

    运行客户端,查看结果

    java zizz.rmi.GreeterClient
  • JDK 5 以及之后的版本,对 RMI 开发进行了很大的改进和简化。主要体现在不再需要手动的对 RMI 服务进行编译生成客户端桩和服务端框架的类文件。