RMI原理浅析

来源:互联网 发布:curl json 编辑:程序博客网 时间:2024/06/18 13:57

之前看过一个RMI的简单示例。这篇文章简单的分析一下RMI的原理。

RMI应用程序的体系结构

上一个例子中,我们编写了两个程序,一个服务端(Server)和一个客户端(Client)。

  • 在Server内创建一个远程对象(CalcServiceImpl),并生成存根,注册到Registry中。
  • 客户端请求远程对象,并调用对象的方法。

RMI架构图

  • Transport Layer:RMI传输层实现网络连接与通信的数据传递。
  • Stub:存根是远程对象在客户端的代理,它驻留在客户端系统中,充当客户端程序的网关。
  • Skeleton:骨架驻留在服务端系统中,Stub通过Skeleton传递参数给远程服务对象。
  • RRL(Remote Reference Layer):RRL是负责管理客户端到远程对象的引用。

RMI的工作原理

  • 当客户端调用远程对象时,它会被Stub接收,并把请求传递给RRL
  • 当客户端RRL接收到请求后,它会调用RemoteRef的invoke()方法。最终这个请求会被传递到服务端的RRL中。
  • 服务端RRL将请求发给Skeleton(服务端的一个代理类),最终调用服务端中的服务对象方法。
  • 服务方法返回的结果按原路返回给客户端。

Marshalling与Unmarshalling

当客户端调用远程对象的方法时,可能需要传递一些参数。这些参数将会被包装在消息中通过网络发送给服务端。这些参数会被序列化成二进制数据流传输到服务端,这个过程也被叫做Marshalling;相反服务端需要把二进制数据流反序列化还原,这个过程也被叫做Unmarshalling

事实上这两个过程使用的使我们非常熟悉的ObjectOutputStream和ObjectInputStream。只不过,RMI进一步包装了这两个类:

Output

Input

这两个过程之间涉及到的消息通信协议,也被称为JRMP协议,Java Remote Message Protocol

RmiRegistry的作用

RmiRegistry用于管理所有的远程服务。

服务器端创建对象时,都会使用Registry.bindRegistry.rebind方法向RmiRegistry注册对象。每个服务对象都对应着一个唯一的服务名。

客户端调用远程对象时,客户端需要远程对象的引用。客户端可以根据服务名调用Registry.lookup方法从RmiRegistry中获取对象。

RmiRegistry

分析Stub中的源代码

在上面的体系架构中,提到了Stub与Skeleton,但是在程序中我们并没有看到这两个类,那是因为从Java 5.0之后,Java使用java.lang.reflect.Proxy为我们动态生成了这两个类。

service.getClass()打印得到的是:class com.sun.proxy.$Proxy0

在Java 5.0之前需要我们使用rmic命令根据服务实现类编译生成存根。

# -keep选项:保留生成的源代码rmic -keep cn.hff.service.CalcServiceImpl

RMIC

生成源码的Stub对象如下:

// Stub class generated by rmic, do not edit.// Contents subject to change without notice.package cn.hff.service;public final class CalcServiceImpl_Stub extends java.rmi.server.RemoteStub implements cn.hff.service.ICalcService {    private static final long serialVersionUID = 2;    private static java.lang.reflect.Method $method_add_0;    private static java.lang.reflect.Method $method_minus_1;    static {        try {            // 获取add方法            $method_add_0 = cn.hff.service.ICalcService.class.getMethod("add",                    new java.lang.Class[] { int.class, int.class });            // 获取minus方法            $method_minus_1 = cn.hff.service.ICalcService.class.getMethod("minus",                    new java.lang.Class[] { int.class, int.class });        } catch (java.lang.NoSuchMethodException e) {            throw new java.lang.NoSuchMethodError("stub class initialization failed");        }    }    // constructors    // 创建CalcServiceImpl_Stub时需要指定RemoteRef    // RemoteRef就是远程对象的引用    public CalcServiceImpl_Stub(java.rmi.server.RemoteRef ref) {        super(ref);    }    // methods from remote interfaces    // implementation of add(int, int)    public int add(int $param_int_1, int $param_int_2) throws java.rmi.RemoteException {        try {            /**             * @param obj:包含RemoteRef的存根对象             * @param method:被调用的方法             * @param params:方法的参数             * @param opnum:被调方法的哈希值             * @return result:返回结果             */            Object $result = ref.invoke(this, $method_add_0,                    new java.lang.Object[] { new java.lang.Integer($param_int_1), new java.lang.Integer($param_int_2) },                    -7734458262622125146L);            return ((java.lang.Integer) $result).intValue();        } catch (java.lang.RuntimeException e) {            throw e;        } catch (java.rmi.RemoteException e) {            throw e;        } catch (java.lang.Exception e) {            throw new java.rmi.UnexpectedException("undeclared checked exception", e);        }    }    // implementation of minus(int, int)    public int minus(int $param_int_1, int $param_int_2) throws java.rmi.RemoteException {        try {            Object $result = ref.invoke(this, $method_minus_1,                    new java.lang.Object[] { new java.lang.Integer($param_int_1), new java.lang.Integer($param_int_2) },                    6403391039451205508L);            return ((java.lang.Integer) $result).intValue();        } catch (java.lang.RuntimeException e) {            throw e;        } catch (java.rmi.RemoteException e) {            throw e;        } catch (java.lang.Exception e) {            throw new java.rmi.UnexpectedException("undeclared checked exception", e);        }    }}

RemoteRef的实现类UnicaseRef的源码可以点击这里查看。