远程方法调用(RMI)原理与示例

RMI介绍

  远程方法调用(RMI)顾名思义是一台机器上的程序调用另一台机器上的方法。这样可以大致知道RMI是用来干什么的,但是这种理解还不太确切。RMI是Java支撑分布式系统的基石,例如著名的EJB组件。RMI是远程过程调用(RPC)的一种面向对象实现,RMI底层是通过socket通信和对象序列化技术来实现的。这里引用Wikipedia对RMI的介绍:

The Java Remote Method Invocation (Java RMI) is a Java API that performs remote method invocation, the object-oriented equivalent of remote procedure calls (RPC), with support for direct transfer of serialized Java classes and distributed garbage collection.

  1. The original implementation depends on Java Virtual Machine(JVM) class representation mechanisms and it thus only supports making calls from one JVM to another. The protocol underlying this Java-only implementation is known as Java Remote Method Protocol (JRMP).
  2. In order to support code running in a non-JVM context, a CORBA version was later developed.

Usage of the term RMI may denote solely the programming interface or may signify both the API and JRMP, IIOP, or another implementation, whereas the term RMI-IIOP (read: RMI over IIOP) specifically denotes the RMI interface delegating most of the functionality to the supporting CORBA implementation.
The basic idea of Java RMI, the distributed garbage-collection (DGC) protocol, and much of the architecture underlying the original Sun implementation, come from the ‘network objects‘ feature of Modula-3.

RMI基本原理

  RMI的目的就是要使运行在不同的计算机中的对象之间的调用表现得像本地调用一样。RMI 应用程序通常包括两个独立的程序:服务器程序和客户机程序。RMI 需要将行为的定义与行为的实现分别定义, 并允许将行为定义代码与行为实现代码存放并运行在不同的 JVM 上。在 RMI 中, 远程服务的定义是存放在继承了 Remote 的接口中。远程服务的实现代码存放在实现该定义接口的类中。RMI 支持两个类实现一个相同的远程服务接口: 一个类实现行为并运行在服务器上, 而另一个类作为一个远程服务的代理运行在客户机上。客户程序发出关于代理对象的调用方法, RMI 将该调用请求发送到远程 JVM 上, 并且进一步发送到实现的方法中。实现方法将结果发送给代理, 再通过代理将结果返回给调用者。

  RMI 构建三个抽象层, 高层覆盖低层, 分别负责Socket通信, 参数和结果的序列化和反序列化等工作。存根( Stub) 和骨架( Skeleton) 合在一起形成了 RMI 构架协议。下面的引用层被用来寻找各自的通信伙伴, 在这一层还有一个提供名字服务的部分, 称为注册表( registry) 。最下一层是传输层, 是依赖于 TCP/IP 协议实现客户机与服务器的互联。
  

  当客户端调用远程对象方法时, 存根负责把要调用的远程对象方法的方法名及其参数编组打包,并将该包向下经远程引用层、传输层转发给远程对象所在的服务器。通过 RMI 系统的 RMI 注册表实现的简单服务器名字服务, 可定位远程对象所在的服务器。该包到达服务器后, 向上经远程引用层, 被远程对象的 Skeleton 接收, 此 Skeleton 解析客户包中的方法名及编组的参数后, 在服务器端执行客户要调用的远程对象方法, 然后将该方法的返回值( 或产生的异常) 打包后通过相反路线返回给客户端, 客户端的 Stub 将返回结果解析后传递给客户程序。事实上, 不仅客户端程序可以通过存根调用服务器端的远程对象的方法, 而服务器端的程序亦可通过由客户端传递的远程接口回调客户端的远程对象方法。在分布式系统中, 所有的计算机可以是服务器, 同时又可以是客户机。

RMI应用示例

  Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在“远程接口”(扩展 java.rmi.Remote 的接口)中指定的这些方法才可远程使用。 也就是说需要远程调用的方法必须在扩展Remote接口的接口中声名并且要抛出RemoteException异常才能被远程调用。远程对象必须实现java.rmi.server.UniCastRemoteObject类,这样才能保证客户端访问获得远程对象时,该远程对象将会把自身的一个拷贝序列化后以Socket的形式传输给客户端,此时客户端所获得的这个拷贝称为“存根”,而服务器端本身已存在的远程对象则称之为“骨架”。其实此时的存根是客户端的一个代理,用于与服务器端的通信,而骨架也可认为是服务器端的一个代理,用于接收客户端的请求之后调用远程方法来响应客户端的请求。 远程对象的接口和实现必须在客户端和服务器端同时存在并且保持一致才行。

实现代码:

package com.wxisme.rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;

/**
 *@Description:<p>远程接口定义</p>
 *@author 王旭
 *@time 2016年3月14日 下午4:53:48
 */
public interface HelloDefine extends Remote {

    public String helloWorld() throws RemoteException;

    public String sayHello(String name) throws RemoteException;

}
package com.wxisme.rmi;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

/**
 *@Description:<p>远程接口实现</p>
 *@author 王旭
 *@time 2016年3月14日 下午4:57:50
 */
public class HelloDefineImp extends UnicastRemoteObject implements HelloDefine {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public HelloDefineImp() throws RemoteException {
        super();
    }

    public String helloWorld() throws RemoteException {
        return "Hello AlphaGo!";
    }

    public String sayHello(String name) throws RemoteException {
        return "Hello" + name +"!";
    }

}
package com.wxisme.rmi;

import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;

/**
 *@Description:<p>服务端绑定</p>
 *@author 王旭
 *@time 2016年3月14日 下午4:59:33
 */
public class HelloServer {

    HelloDefine hello;

    public void server() throws RemoteException, MalformedURLException, AlreadyBoundException {
        hello = new HelloDefineImp();

        //远程对象注册表实例
        LocateRegistry.createRegistry(8888);
        //把远程对象注册到RMI注册服务器上
        Naming.bind("rmi://localhost:8888/Hello", hello);
        System.out.println("server:对象绑定成功!");
    }

}
package com.wxisme.rmi;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

/**
 *@Description:<p>客户端调用</p>
 *@author 王旭
 *@time 2016年3月14日 下午5:08:51
 */public class HelloClient {

    public HelloDefine hello;

    public void client() throws MalformedURLException, RemoteException, NotBoundException {
        //在RMI注册表中查找指定对象
        hello = (HelloDefine) Naming.lookup("rmi://localhost:8888/Hello");
        //调用远程对象方法
        System.out.println("client:");
        System.out.println(hello.helloWorld());
        System.out.println(hello.sayHello("神之一手"));
    }

}
package com.wxisme.rmi;

import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

import org.junit.Test;

/**
 *@Description:<p>测试</p>
 *@author 王旭
 *@time 2016年3月14日 下午5:14:36
 */
public class RMITest {

    @Test
    public void testServer() throws RemoteException, MalformedURLException, AlreadyBoundException {
        HelloServer server = new HelloServer();
        server.server();
        while(true);
    }

    @Test
    public void testClient() throws MalformedURLException, RemoteException, NotBoundException {
        HelloClient client = new HelloClient();
        client.client();
    }

}

运行结果:

参考资料:

Wikipedia RMI:https://en.wikipedia.org/wiki/Java_remote_method_invocation

Java RMI 框架:http://haolloyin.blog.51cto.com/1177454/332426/

《基于 RMI 的文件上传与下载的实现》程晓锦, 徐秀花

时间: 2024-08-07 17:02:25

远程方法调用(RMI)原理与示例的相关文章

远程方法调用——RMI

RMI RMI  (Remote  Method  Invocation)是Java用于实现透明远程调用的重要机制.在远程调用中,客户端仅有服务器端提供的接口 .通过此接口实现对远程服务器端的调用.其威力就体现在它强大的开发分布式网络应用的能力上,是纯Java的网络分布式应用系统的核心解决方案之一.其实它可以被看作是RPC的Java版本.但是传统RPC并不能很好地应用于分布式对象系统.而Java RMI 则支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用. Su

格式化字符串攻击原理及示例.RP

格式化字符串攻击原理及示例 一.类printf函数簇实现原理 类printf函数的最大的特点就是,在函数定义的时候无法知道函数实参的数目和类型. 对于这种情况,可以使用省略号指定参数表. 带有省略号的函数定义中,参数表分为两部分,前半部分是确定个数.确定类型的参数,第二部分就是省略号,代表数目和类型都不确定的参数表,省略号参数表中参数的个数和参数的类型是事先的约定计算出来的,每个实参的地址(指针)是根据确定参数表中最后一个实参的地址算出来的. 这里涉及到函数调用时的栈操作.函数栈的栈底是高地址,

远程方法调用(RMI)原理与示例 (转)

RMI介绍 远程方法调用(RMI)顾名思义是一台机器上的程序调用另一台机器上的方法.这样可以大致知道RMI是用来干什么的,但是这种理解还不太确切.RMI是Java支撑分布式系统的基石,例如著名的EJB组件.RMI是远程过程调用(RPC)的一种面向对象实现,RMI底层是通过socket通信和对象序列化技术来实现的.这里引用Wikipedia对RMI的介绍: The Java Remote Method Invocation (Java RMI) is a Java API that perform

Struts2单文件上传原理及示例

一.文件上传的原理 表单元素的enctype属性指定的是表单数据的编码方式,该属性有3个值: 1.application/x-www-form-urlencoded:这是默认编码方式,它只处理表单域里的value属性值,采用这种编码方式的表单会将表单域的值处理成URL编码方式. 2.multipart/form-data:这种编码方式的表单会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数里. 3.text/plain:这种方式主要适用于直接通过表单发送邮件的

javascript 作用域 闭包 对象 原理和示例分析(上)

                                                                                             阅读.理解.思考.实践,再实践.再思考....  深圳小地瓜献上 javascript高级特性包含:作用域.闭包.对象 -----------------------------------------------作用域-----------------------------------------------

javascript回调函数(模式)原理和示例深入分析

   广大网友读懂了我之前论述的javascript原理这篇文章很容易懂 回调函数来自一种著名的编程范式--函数式编程,在基本层面上,函数式编程指定的了函数的参数.函数式编程虽然现在的使用范围变小了,但它一直被"专业的聪明的"程序员看作是一种难懂的技术,以前是这样,未来也将是如此. 幸运的是,函数式编程已经被阐述的像你我这样的一般人也能理解和使用.函数式编程最主要的技术之一就是回调函数,你很快会阅读到,实现回调函数就像传递一般的参数变量一样简单.这项技术如此的简单,以至于我都怀疑为什么

RSA算法原理及示例

可以先看看这个视频: RSA_Encryption_Algorithm 公开密钥 Perwork: 私钥:Sender和Receiver预先约定加密和解密方案,向其他人保密. 这个实现比较难:向其他人保密.假如你是个商家,很多人要和你联络,发送者可能和你一点关系也没有,怎么保密. 需求:Sender素不相识,发送消息需求保密,加密方案必须公开.[就和信箱一样,所有人都可以向你公开的的信箱里投信件,但是只有你才有钥匙(私有的)取信件] 公钥:加密方案向所有人公开,解密方案只有Receiver知道,

远程方法调用(RMI)

什么是RMI? Java远程方法调用(Java RMI)是Java API对远程过程调用(RPC)提供的面向对象的等价形式,支持直接传输序列化的Java对象和分布式垃圾回收.远程方法调用可以看做是激活远程正在运行的对象上的方法的步骤.RMI对调用者是位置透明的,因为调用者感觉方法是执行在本地运行的对象上的.看下RMI的一些注意事项. RMI 指的是远程方法调用 (Remote Method Invocation).它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中

nio原理和示例代码

我正在为学习大数据打基础中,为了手撸rpc框架,需要懂得nio的原理,在搞懂nio框架前,我会带着大家手撸一些比较底层的代码,当然今后当我们学会了框架,这些繁琐的代码也就不用写了,但是学一学底层的代码也是有好处的嘛. java.nio全称java non-blocking IO(实际上是 new io),是指jdk1.4 及以上版本里提供的新api(New IO) ,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络. 前面我写的socket的