RMI(Remote Method Invocation)是Java中的远程过程调用(Remote Procedure Call,RPC)实现,是一种分布式Java应用的实现方式。它的目的在于对开发人员屏蔽横跨不同JVM和网络连接等细节,使得分布在不同JVM上的对象像是存在于一个统一的JVM中一样,可以很方便的互相通讯。之所以在介绍对象序列化之后来介绍RMI,主要是因为对象序列化机制使得RMI非常简单。调用一个远程服务器上的方法并不是一件困难的事情。开发人员可以基于Apache MINA或是Netty这样的框架来写自己的网络服务器,亦或是可以采用REST架构风格来编写HTTP服务。但这些解决方案中,不可回避的一个部分就是数据的编排和解排(marshal/unmarshal)。需要在Java对象和传输格式之间进行互相转换,而且这一部分逻辑是开发人员无法回避的。RMI的优势在于依靠Java序列化机制,对开发人员屏蔽了数据编排和解排的细节,要做的事情非常少。JDK 5之后,RMI通过动态代理机制去掉了早期版本中需要通过工具进行代码生成的繁琐方式,使用起来更加简单。
RMI采用的是典型的客户端-服务器端架构。首先需要定义的是服务器端的远程接口,这一步是设计好服务器端需要提供什么样的服务。对远程接口的要求很简单,只需要继承自RMI中的Remote接口即可。Remote和Serializable一样,也是标记接口。远程接口中的方法需要抛出RemoteException。定义好远程接口之后,实现该接口即可。如下面的Calculator是一个简单的远程接口。
public interface Calculator extends Remote { String calculate(String expr) throws RemoteException;}
实现了远程接口的类的实例称为远程对象。创建出远程对象之后,需要把它注册到一个注册表之中。这是为了客户端能够找到该远程对象并调用。
public class CalculatorServer implements Calculator { public String calculate(String expr) throws RemoteException { return expr; } public void start() throws RemoteException, AlreadyBoundException { Calculator stub = (Calculator) UnicastRemoteObject.exportObject(this, 0); Registry registry = LocateRegistry.getRegistry(); registry.rebind("Calculator", stub); }}
CalculatorServer是远程对象的Java类。在它的start方法中通过UnicastRemoteObject的exportObject把当前对象暴露出来,使得它可以接收来自客户端的调用请求。再通过Registry的rebind方法进行注册,使得客户端可以查找到。
客户端的实现就是首先从注册表中查找到远程接口的实现对象,再调用相应的方法即可。实际的调用虽然是在服务器端完成的,但是在客户端看来,这个接口中的方法就好像是在当前JVM中一样。这就是RMI的强大之处。
public class CalculatorClient { public void calculate(String expr) { try { Registry registry = LocateRegistry.getRegistry("localhost"); Calculator calculator = (Calculator) registry.lookup("Calculator"); String result = calculator.calculate(expr); System.out.println(result); } catch (Exception e) { e.printStackTrace(); } }}
在运行的时候,需要首先通过rmiregistry命令来启动RMI中用到的注册表服务器。
为了通过Java的序列化机制来进行传输,远程接口中的方法的参数和返回值,要么是Java的基本类型,要么是远程对象,要么是实现了 Serializable接口的Java类。当客户端通过RMI注册表找到一个远程接口的时候,所得到的其实是远程接口的一个动态代理对象。当客户端调用其中的方法的时候,方法的参数对象会在序列化之后,传输到服务器端。服务器端接收到之后,进行反序列化得到参数对象。并使用这些参数对象,在服务器端调用实际的方法。调用的返回值Java对象经过序列化之后,再发送回客户端。客户端再经过反序列化之后得到Java对象,返回给调用者。这中间的序列化过程对于使用者来说是透明的,由动态代理对象自动完成。除了序列化之外,RMI还使用了动态类加载技术。当需要进行反序列化的时候,如果该对象的类定义在当前JVM中没有找到,RMI会尝试从远端下载所需的类文件定义。可以在RMI程序启动的时候,通过JVM参数java.rmi.server.codebase来指定动态下载Java类文件的URL。
相关推荐
通过以上对Java RMI的详细介绍,我们可以看出Java RMI不仅为开发者提供了强大的分布式应用开发能力,而且还提供了丰富的高级特性,使得开发者能够更加专注于业务逻辑的实现,而无需过多关心底层通信细节。...
Java Remote Method Invocation (RMI) 是Java平台中用于构建分布式应用程序的一种关键技术。RMI允许Java对象在不同的Java...实践中,结合这些知识,可以进一步探索RMI的高级特性,如异步调用、异常处理和安全控制等。
4. **EJB与RMI-IIOP的关系**:比较EJB中的RMI-IIOP使用与普通Java RMI的区别,理解EJB如何提供更高级的服务和管理功能。 5. **测试与调试**:通过运行批处理命令,观察服务的启动和客户端调用过程,学习如何调试...
尽管Java RMI相对简单,但CORBA提供了更高级的功能,如事务管理、安全性和更强大的命名服务。在Java中实现CORBA,通常涉及以下步骤: 1. 编写IDL接口定义文件,描述对象的接口和方法。 2. 使用`idlj`工具将IDL编译...
1. **RMI概念**:RMI是Java语言中的一个特性,它使Java对象能够在网络环境中像本地调用一样调用远程对象的方法。这种机制基于Java序列化和动态代理,使得Java应用程序可以跨越网络边界进行通信。 2. **RMI架构**:...
- **存根和骨架**: RMI-IIOP通信中的中间件组件。 - **会话Bean**: 用于实现业务逻辑的Bean。 - **无状态会话bean**: 不保存客户端状态的会话Bean。 - **有状态会话bean**: 保存客户端状态的会话Bean。 - **实体Bean...
在Dubbo这个高性能、轻量级的开源Java RPC框架中,服务运行的三种方式是其核心功能之一,它们分别是:本地存根(Local Stub)、远程代理(Remote Proxy)以及缓存代理(Cache Proxy)。理解这三种方式对于优化服务...
- **rmi://**:使用RMI协议进行远程方法调用。 - **hessian://**:使用Hessian协议进行远程方法调用。 - **http://**:使用HTTP协议进行远程方法调用。 - **webservice://**:使用WebService协议进行远程方法调用。 ...