Java -- 远程程序调用(Remote Method Invocation RMI)

引言

一般Java的方法调用都是对运行在相同Java虚拟机上的对象进行的,也就是调用方法与被调用方法都是在同一个堆上。

如果要调用不同机器上的对象的方法呢?这就要用到RMI技术。

远程过程调用的设计

要创建出4种东西:服务器、客户端、服务器辅助设施、客户端辅助设施

1.创建客户端和服务器应用程序

2.创建服务器和客户端的 辅助设施(helper)。它们会处理所有客户端和服务器的低层网络输入/输出细节,让你的客户端和程序好像在处理本机的调用一样。

辅助设施的任务

辅助设施是个实际上执行通信的对象。让你的客户端和程序好像在处理本机的调用一样。客户端以为它调用的是远程服务,因为辅助设施假装成该服务对象。

但客户度辅助设施不是真正的远程服务,它没有真正客户端需要的方法逻辑。相反,辅助设施会去连接服务器,将调用信息传送过去(比如方法的名称和参数),然后等待服务器响应。

服务器端,服务器辅助设施通过socket连接来自客户端辅助设施的要求,解析打包来的信息,然后调用真正的服务。因此对服务对象来说此调用来自本地。

服务器辅助设施取得返回值后送回去(通过socket输出串流)给客户端辅助设施。客户端辅助设施会解开这些信息传给客户端对象。

Java RMI 提供客户端和服务器端的辅助设施对象

在Java中 RMI已经帮你创建好客户端和服务器端的辅助设施。

RMI中 客户端的辅助设施称为stub,服务器端的辅助设施称为skeleton

RMI 的协议

使用RMI时有2种协议: JRMP或是IIOP

JRMP:RMI的原生协议,它是为了Java对Java间的远程调用而设计的。

IIOP:为了CORBA(Common Object Request Broker Architecture)而产生的,它让你能够调用Java对象或其他类型的远程方法。

CORBA通常比RMI麻烦,因为若两端不全都是Java的话,就会发生一些可怕的转译和交谈操作。

创建远程服务

步骤1:创建远程接口

// 1.继承java.rmi.Remote
// Remote是个标记性接口,没有方法。接口是可以继承其他接口的,使用extends关键字。
// 2.声明所有方法都会抛出java.rmi.RemoteException    
// 3.确定所有参数和返回值类型都是基本类型或可序列化的对象
// 任何远程方法的参数都会被打包通过网络传送,而这是通过序列化实现的。返回值也一样。
public interface MyRemote extends Remote {
    public String sayHello() throws java.rmi.RemoteException;
}

步骤2:实现远程接口

// 继承java.rmi.server.UnicastRemoteObject
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
    // 1.实现MyRemote接口
    // 2.提供一个无参构造器,调用父类的无参构造器
    public MyRemoteImpl() throws java.rmi.RemoteException {
    }
    
    // 3.实现sayHello方法
    @Override
    public String sayHello() {
        return "Server says, 'Hey there!'";
    }
    
    public static void main(String[] args) {
        try {
            // 4.创建MyRemoteImpl对象
            MyRemoteImpl remote = new MyRemoteImpl();
            
            // 5.注册远程对象到RMI注册表.RMI系统会把stub加到注册表中
            java.rmi.Naming.rebind("Remote Hello", remote);
            
            System.out.println("Server is ready.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }   
}

步骤3:产生stub和skeleton

1.对实现出的类执行rmic。 从实现类所在目录执行rmic。

rmic 编译 器 (JDK自带)根据 编译 后的 Java 类 (含有 远 程 对 象 实现 )名,为远程对象生成 stub 和 skeleton( 远 程 对 象是指 实现 java.rmi .Remote 接口的 对 象)。在 rmic 命令中所 给 的 类 必 须 是 经 javac 命令成功 编译 且是完全包限定的 类 。

命令代码:rmic MyRemoteImpl

从 Java 11 开始,rmic 工具已被移除

步骤4:执行rmiregistry

从类这个目录来运行。

命令代码:rmiregistry

RMI registry 必须在同一台机器上与远程服务一块执行,且必须在对象的注册之前启动。

步骤5:启动服务

调用另一个命令行来启动服务

命令代码:java MyRemoteImpl

客户端程序代码

public class MyRemoteClient {
    public static void main(String[] args) {
        new MyRemoteClient().go();
    }

    public void go() {
        try {
            // 1.客户端查找RMI注册表中的远程对象
            // Naming.lookup()方法的参数是一个URL字符串,格式为"rmi://host:port/name"。
            // 2.RMI注册表返回stub对象
            MyRemote service = (MyRemote) Naming.lookup("rmi:127.0.0.1/Remote Hello");
            String s = service.sayHello();  // 2.调用远程方法
            System.out.println("Server says: " + s);  // 3.输出结果
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以上是RMI的简单示例,如果深入探索,也许你会加入Jini查询服务等待,具体如何使用需要读者自己去发现了。

posted @ 2025-07-07 14:39  NE_STOP  阅读(45)  评论(0)    收藏  举报