第一个Dubbo应用之RMI

转自:http://dubbo.apache.org/zh-cn/blog/dubbo-101.html

Java RMI 简介

Java RMI (Remote Method Invocation)- 远程方法调用,能够让客户端像使用本地调用一样调用服务端 Java 虚拟机中的对象方法。RMI 是面向对象语言领域对 RPC (Remote Procedure Call)的完善,用户无需依靠 IDL 的帮助来完成分布式调用,而是通过依赖接口这种更简单自然的方式。

Java RMI 工作原理

一个典型的 RMI 调用如下图所示:

  1. 服务端向 RMI 注册服务绑定自己的地址,
  2. 客户端通过 RMI 注册服务获取目标地址,
  3. 客户端调用本地的 Stub 对象上的方法,和调用本地对象上的方法一致,
  4. 本地存根对象将调用信息打包,通过网络发送到服务端,
  5. 服务端的 Skeleton 对象收到网络请求之后,将调用信息解包,
  6. 然后找到真正的服务对象发起调用,并将返回结果打包通过网络发送回客户端。

Java RMI 基本概念

Java RMI 是 Java 领域创建分布式应用的技术基石。后续的 EJB 技术,以及现代的分布式服务框架,其中的基本理念依旧是 Java RMI 的延续。在 RMI 调用中,有以下几个核心的概念:

  1. 通过接口进行远程调用

  2. 通过客户端的 Stub 对象和服务端的 Skeleton 对象的帮助将远程调用伪装成本地调用

  3. 通过 RMI 注册服务完成服务的注册和发现

对于第一点,客户端需要依赖接口,而服务端需要提供该接口的实现。

对于第二点,在 J2SE 1.5 版本之前需要通过 rmic 预先编译好客户端的 Stub 对象和服务端的 Skeleton 对象。在之后的版本中,不再需要事先生成 Stub 和 Skeleton 对象。

下面通过示例代码简单的展示 RMI 中的服务注册和发现

服务端的服务注册

Hello obj = new HelloImpl(); // #1
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0); // #2
Registry registry = LocateRegistry.createRegistry(1099); // #3
registry.rebind("Hello", stub); // #4

说明:

  1. 初始化服务对象实例,
  2. 通过 UnicastRemoteObject.exportObject 生成可以与服务端通讯的 Stub 对象,
  3. 创建一个本地的 RMI 注册服务,监听端口为 1099。该注册服务运行在服务端,也可以单独启动一个注册服务的进程,
  4. 将 Stub 对象绑定到注册服务上,这样,客户端可以通过 Hello 这个名字查找到该远程对象。

客户端的服务发现

Registry registry = LocateRegistry.getRegistry(); // #1
Hello stub = (Hello) registry.lookup("Hello"); // #2
String response = stub.sayHello(); // #3

说明:

  1. 获取注册服务实例,在本例中,由于没有传入任何参数,假定要获取的注册服务实例部署在本机,并监听在 1099 端口上,
  2. 从注册服务中查找服务名为 Hello 的远程对象,
  3. 通过获取的 Stub 对象发起一次 RMI 调用并获得结果。

理解 RMI 的工作原理和基本概念,对掌握现代分布式服务框架很有帮助,建议进一步的阅读 RMI 官方教材(https://docs.oracle.com/javase/6/docs/technotes/guides/rmi/hello/hello-world.html)。