2.6 远端方法调用时的参数传递
一个远端对象只要可以序列化就可以是方法参数或是返回值。这就包括了基础对象、远端对象和实现了java.io.Serializable的非远端对象。更多关于如何序列化类的信息科一参考 “Java Object Serialization Specification”。这些参数或者返回值不是本地的,它们是通过RMI系统动态下载的。更多细节查看Dynamic Class Loading
2.6.1 传递非远端对象
一个非远端对象,无论是作为参数还是返回值,它都是通过复制来传递的,也就是通过java的序列化机制序列化后得到的。
所以,在方法调用过程中,当一个远端对象作为参数或者返回值被传递时,这个非远端对象的内容会在方法调用前被复制。
当调用远端方法返回一个非远端对象时,本地虚拟机就会创建一个新的对象。
2.6.2 传递远端对象
当传递一个远端对象时,实际传递的是这个对象的存根(stub)。
没有暴露的远端对象不会被存根实例替代。远端对象只有实现了远端接口才可以作为参数被传递。
2.6.3 引用的完整性(Referential Integrity)
如果一个对象的两个引用作为一个远端方法的参数从一个虚拟机传递到另一个虚拟机,那么这些引用在发送对象的虚拟机中指向的是同一个对象,它们在接收对象的虚拟机中指向的是同一个对象的副本,RMI系统会在对象传递过程中保证引用的完整性。
2.6.4 类注释(Class Annotation)
当一个对象通过方法调用,从一个虚拟机传递到另一个虚拟机时,RMI系统会通过URL来标识这个类,以便可以在接收端加载这个类。这个要求保证类会按需下载。
(这里翻译的感觉有点问题,下面是原文)
When an object is sent from one JVM to another in a remote method call, the RMI system annotates the class descriptor in the call stream with information (the URL) of the class so that the class can be loaded at the receiver. It is a requirement that classes be downloaded on demand during remote method invocation.
2.6.5 参数传递
在RMI调用中参数被写到流中,该流是java.io.ObjectOutputStream的子类,这样是为了可以将参数序列化到远端调用虚拟机中。ObjectOutputStream子类会重写replaceObject方法,该方法用每一个暴露的远端对象所对应的存根实例来替换他们。参数这些对象是通过ObjectOutputStream的writeObject方法来写入流中的。ObjectOutputStream会为每一个通过writeObject方法写入流的对象调用replaceObject方法(包括写入对象所引用的对象)。replaceObject方法返回结果如下:
1、如果这个对象实现了java.rmi.Remote而且这个对象在RMI运行时被导出,那么该方法返回这个对象的存根实例。如果这个对象实现了java.rmi.Remote,但是没有在RMI运行时被导出,那么replaceObject方法返回该对象本身。对于远端对象的存根,可以通过调用java.rmi.server.RemoteObject的toStub方法获得。
2、如果这个对象不是一个java.rmi.Remote的实例,那么会简单返回该对象。
RMI中ObjectOutputStream的子类也会实现annotateClass方法,该类会通过远端类的位置来对类进行解释说明,以便该类可以在接收端被下载。
因为参数写入是通过一个单独的ObjectOutputStream,所以同一个对象的引用在接收端会指向同一个对象的副本。在接收端,参数通过一个单独的ObjectInputStream读出来。
ObjectOutputStream的其他任何写对象的行为(ObjectInputStream的读取对象和它类似)都是在参数传递中维护的。比如说,在写对象是会调用writeReplace方法,在读对象的时候回调用readResolve方法,这些方法都是由RMI参数的编排或者反编排流提供的。
返回值和异常的传递和上面讲的参数传递类似。