📜  Java中的远程方法调用RMI

📅  最后修改于: 2020-04-02 05:18:41             🧑  作者: Mango

远程方法调用(RMI)是一种API,它允许对象在存在于另一个地址空间中对象上调用方法,该地址空间可以在同一台计算机上,也可以在远程计算机上。通过RMI,在计算机(客户端)上存在的JVM中运行的对象可以调用另一个JVM(服务器端)中存在的对象上的方法。RMI创建一个公共的远程服务器对象,该对象通过对服务器对象的简单方法调用来实现客户端和服务器端的通信。

RMI的工作
客户端和服务器之间的通信通过使用两个中间对象来处理:Stub对象(在客户端)和Skeleton对象(在服务器端)。

存根Stub对象
客户端计算机上的存根对象将构建一个信息块,并将此信息发送到服务器。该块包括

  • 要使用的远程对象的标识符
  • 要调用的方法名称
  • 远程JVM的参数

Skeleton对象
Skeleton对象将请求从存根Stub对象递到远程对象。它执行以下任务

  • 它在服务器上存在的真实对象上调用所需的方法。
  • 它将从存根对象接收的参数转发到方法。

实施接口的步骤

  1. 定义远程接口
  2. 实现远程接口
  3. 使用Rmic(RMI Complier)从实现类创建Stub和Skeleton对象
  4. 启动rmiregistry
  5. 创建并执行服务器应用程序
  6. 创建并执行客户端应用程序。

步骤1:定义远程接口
首先要做的是创建一个接口,该接口将提供可被远程客户端调用的方法的描述。此接口应扩展Remote接口,并且该接口内的方法原型应引发RemoteException。

// 创建一个Search接口
import java.rmi.*;
public interface Search extends Remote
{
    // 声明方法原型
    public String query(String search) throws RemoteException;
}

步骤2:实现远程接口
下一步是实现远程接口。要实现远程接口,该类应扩展java.rmi包的UnicastRemoteObject类。另外,需要创建一个默认构造函数以从其父构造函数在类中抛出Java.rmi.RemoteException。

// Java程序,实现一个Search接口
import java.rmi.*;
import java.rmi.server.*;
public class SearchQuery extends UnicastRemoteObject
                         implements Search
{
    // 默认构造函数,从父类报错RemoteException
    SearchQuery() throws RemoteException
    {
        super();
    }
    // 实现query接口
    public String query(String search)
                       throws RemoteException
    {
        String result;
        if (search.equals("Java的反射"))
            result = "有";
        else
            result = "无";
        return result;
    }
}

步骤3:使用rmic从实现类中创建Stub和Skeleton对象
rmic工具用于调用创建Stub和Skeleton对象的rmi编译器,它的原型是Rmic类。对于上面的程序,需要在命令提示符下执行以下命令

rmic SearchQuery

步骤4:启动rmiregistry
通过在命令提示符处发出以下命令,启动注册表服务start rmiregistry

步骤5:创建并执行服务器应用程序
下一步是创建服务器应用程序并在单独的命令提示符下执行它。

  • 服务器程序使用LocateRegistry类的createRegistry方法在服务器JVM中创建rmiregistry,并将端口号作为参数传递。
  • Naming类的rebind方法用于将远程对象绑定到新名称。
    // server端Java程序
    import java.rmi.*;
    import java.rmi.registry.*;
    public class SearchServer
    {
        public static void main(String args[])
        {
            try
            {
                // 创建对象
                Search obj = new SearchQuery();
                // JVM注册端口1900
                LocateRegistry.createRegistry(1900);
                
                // 绑定远程对象名为mango
                Naming.rebind("rmi://localhost:1900"+
                              "/mango",obj);
            }
            catch(Exception ae)
            {
                System.out.println(ae);
            }
        }
    }

步骤6:创建和执行客户端应用程序
最后一步是创建客户端应用程序,并在单独的命令提示符下执行它。Naming类的lookup方法用于获取Stub对象的引用。

// 创建客户端应用程序
import java.rmi.*;
public class ClientRequest
{
    public static void main(String args[])
    {
        String answer,value="Reflection in Java";
        try
        {
            // lookup 方法来寻找远程的对象
            Search access =
                (Search)Naming.lookup("rmi://localhost:1900"+
                                      "/mango");
            answer = access.query(value);
            System.out.println("Article on " + value +
                            " " + answer+" at mango");
        }
        catch(Exception ae)
        {
            System.out.println(ae);
        }
    }
}

注意:上面的客户端和服务器程序在同一台计算机上执行,因此使用localhost。为了从另一台计算机访问远程对象,localhost将被替换为存在远程对象的IP地址。
重要的点:

  1. RMI是远程过程调用(RPC)的纯Java解决方案,用于在Java中创建分布式应用程序。
  2. Stub和Skeleton对象用于客户端和服务器端之间的通信。