文章摘要: 允许一个 Java 虚拟机上的对象调用另一个 Java 虚拟机上对象的方法。
介绍
简要说明
- 允许一个 Java 虚拟机上的对象调用另一个 Java 虚拟机上对象的方法。
- 实现远程过程调用(RPC)机制,使得在不同 JVM 之间可以进行方法调用,就像本地调用一样。
主要功能
- 远程对象:允许对象在不同 JVM 之间进行通信,这些对象被称为远程对象。
- stub 和 skeleton:stub 是远程对象的本地代理,它负责将调用转发给远程对象。skeleton 是在服务器端运行的,用于接收来自 stub 的调用并转发给实际的远程对象。
- RMI 注册表:提供了一个注册表服务,允许远程对象通过名称绑定和查找。
- RMI 查找:客户端使用 Naming 类来查找远程对象。
- 远程接口:定义了远程对象必须实现的接口,这些接口的方法可以远程调用。
- 序列化:RMI 使用 Java 序列化机制来传输对象,因此远程对象及其参数和返回值必须实现
Serializable接口。
注意事项
- 安全性:RMI 调用可能会跨越不安全的网络,因此需要考虑使用安全策略文件来限制远程对象的访问。
- 异常处理:远程方法调用可能会抛出
RemoteException,调用者需要捕获并处理这些异常。 - 性能:RMI 调用涉及网络通信,因此性能可能不如本地方法调用。应尽量减少远程调用次数,并优化数据传输。
- 防火墙和端口:RMI 需要特定的端口来通信,可能需要在防火墙上配置端口转发规则。
- 版本兼容性:客户端和服务器端的远程接口和实现类需要保持版本兼容,否则可能发生序列化错误。
适用场景
- 分布式系统:在分布式系统中,不同服务器上的组件需要相互通信和协作。
- 远程服务:创建可以被远程客户端调用的服务,如数据库服务、文件服务等。
- 跨网络操作:在需要跨网络执行操作的场景,例如在不同的数据中心之间同步数据。
- 企业应用集成:在企业应用集成中,使用 RMI 可以实现不同系统之间的方法调用和数据交换。
主要概念
远程接口(Remote Interface)
远程接口是标记接口,用于指示哪些方法可以从远程 Java 虚拟机上调用。任何实现远程接口的类都必须声明为 Serializable,并且其所有方法都必须抛出 RemoteException。
远程对象(Remote Object)
实现了远程接口的类的实例,可以被远程访问。
Stub 和 Skeleton
- Stub: 是远程对象的本地代理,它实现了远程接口,并负责将调用转发给远程对象。
- Skeleton: 是一个存在于服务器端的辅助类,它负责接收来自网络的调用,并将它们传递给远程对象。从 Java 2 平台开始,Skeleton 类在运行时自动生成,因此不再需要手动编写。
RMI 注册表(RMI Registry)
RMI 注册表是一个服务,它允许远程客户端查找并调用服务器上的远程对象。
主要类和接口
RemoteException
RemoteException是大多数 RMI 方法抛出的异常,表示在远程方法调用过程中发生了错误。
Remote
Remote是一个标记接口,用于指示对象可以接受远程调用。
RemoteObject
RemoteObject是Remote接口的直接实现,提供了支持远程对象实现的基本功能。
UnicastRemoteObject
UnicastRemoteObject是RemoteObject的子类,用于创建单播远程对象,即一次只能由一个客户端调用的对象。
Naming
Naming类提供了用于将远程对象绑定到 RMI 注册表和查找远程对象的方法。bind(String name, Remote obj): 将指定的名称绑定到远程对象。lookup(String name): 查找并返回指定名称的远程对象引用。
RMISecurityManager
RMISecurityManager是用于 RMI 调用的安全管理器,负责检查权限。
学习总结
创建远程对象
- 定义一个远程接口,该接口扩展
Remote并声明要远程调用的方法。 - 实现该接口,并在实现类中扩展
UnicastRemoteObject。 - 通过
exportObject方法导出远程对象。
注册远程对象
- 启动 RMI 注册表服务。
- 使用
Naming类的bind方法将远程对象绑定到注册表中。
访问远程对象
- 使用
Naming类的lookup方法从注册表中获取远程对象的引用。 - 调用远程对象的方法,就像调用本地对象一样。
注意事项
- 序列化: 远程对象及其参数和返回值必须实现
Serializable接口。 - 异常处理: 所有远程方法都必须声明抛出
RemoteException。 - 安全性: RMI 调用可能会跨越不同的安全域,因此需要考虑安全性和权限管理。
- 网络: RMI 调用依赖于网络,因此网络配置和防火墙设置可能会影响 RMI 的使用。
RMI 的局限性
- RMI 仅限于 Java 环境,不支持跨语言调用。
- 性能可能不如其他 RPC 框架,如 gRPC 或 Apache Thrift。
- 配置较为复杂,尤其是在涉及安全性和网络问题时。
java.rmi.activation
提供对 RMI 对象激活的支持。
java.rmi.dgc
为 RMI 分布式垃圾回收 (DGC) 提供类和接口。
java.rmi.registry
为 RMI 注册表提供一个类和两个接口。
java.rmi.server
提供用于支持 RMI 服务器端的类和接口。