java RMI的工作过程

Java RMI通过定义继承Remote的接口(如MyService)、实现类(如MyServiceImpl)、启动rmiregistry并绑定服务(Naming.rebind)、客户端

查找存根(Naming.lookup)并调用方法,实现远程对象调用。整个过程由RMI自动处理序列化、网络传输和方法转发,使远程调用如同本地调用一样透明。

Java RMI(Remote Method Invocation)允许一个Java虚拟机上的对象调用另一个Java虚拟机上的对象方法,实现远程过程调用。它的核心是让远程调用看起来像本地调用一样,屏蔽网络通信的复杂性。

1. 定义远程接口

远程对象的方法必须通过一个继承java.rmi.Remote的接口来声明。接口中的每个方法都必须声明抛出RemoteException,表示可能因网络问题失败。

- 接口定义服务提供哪些可被远程调用的方法。 - 例如:
public interface MyService extends Remote {
String sayHello() throws RemoteException;
}

2. 实现远程接口

创建一个类实现上面定义的远程接口,并提供具体逻辑。这个类的实例将作为远程对象被客户端调用。

- 实现类通常继承UnicastRemoteObject,以便自动支持远程通信。 - 构造函数会抛出RemoteException,因为需要导出对象到RMI运行时。 - 示例:
public class MyServiceImpl extends UnicastRemoteObject implements MyService {
protected MyServiceImpl() throws RemoteException { super(); }
public String sayHello() throws RemoteException { return "Hello from server"; }
}

3. 启动RMI注册表并绑定服务

RMI注册表(rmiregistry)是一个命名服务,用来注册远程对象并供客户端查找。

- 可以通过命令行启动:`rmiregistry 1099`(默认端口1099)。 - 在服务端代码中,使用Naming.rebind()Registry.bind()把远程对象绑定到一个名称上。 - 例如:
MyService service = new MyServiceImpl();
Naming.rebind("rmi://localhost/MyService", service);

4. 客户端查找并调用远程方法

客户端通过RMI注册表查找远程对象的引用,然后像调用本地对象一样调用其方法。

- 使用Naming.lookup()根据URL获取远程对象的存根(stub)。 - 存根是远程对象的代理,负责将方法调用封装成网络请求发送给服务端。 - 示例:
MyService stub = (MyService) Naming.lookup("rmi://localhost/MyService");
String result = stub.sayHello(); // 实际发生远程调用

整个过程中,RMI自动处理了序列化、网络传输、方法转发和结果返回。客户端持有的是stub,服务端有skeleton(在新版本中已隐式处理),两者完成跨JVM通信。

基本上就这些。只要接口规范、网络通畅、类路径正确,RMI就能透明地完成远程调用。