Java RMI远程方法调用:从入门到精通完整教程

2024-06-21 超腾开源 182 次阅读 0 次点赞
Java RMI是Java平台原生支持的远程方法调用机制,允许不同JVM上的对象相互调用方法。本文系统讲解RMI的四大核心组件:远程接口、远程对象实现、RMI注册表和客户端,通过完整的计算器服务示例展示从接口定义、服务实现到部署运行的全过程,并分析RMI在分布式系统中的优势与限制,为Java开发者提供实用的分布式编程解决方案。

Java RMI (Remote Method Invocation) 是Java平台的远程方法调用机制,允许一个Java虚拟机上的对象调用另一个Java虚拟机上的对象方法,就像调用本地对象一样。

RMI 核心组件

1、远程接口 - 定义可远程调用的方法

2、远程对象实现 - 实现远程接口的具体类

3、RMI 注册表 - 服务注册和查找的命名服务

4、客户端 - 调用远程方法的程序

示例代码

1. 定义远程接口

// Calculator.java
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {
    // 所有远程方法必须声明抛出RemoteException
    double add(double a, double b) throws RemoteException;
    double subtract(double a, double b) throws RemoteException;
    double multiply(double a, double b) throws RemoteException;
    double divide(double a, double b) throws RemoteException;
}

2. 实现远程接口

// CalculatorImpl.java
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class CalculatorImpl extends UnicastRemoteObject implements Calculator {
    
    // 必须提供构造函数并抛出RemoteException
    public CalculatorImpl() throws RemoteException {
        super();
    }
    
    @Override
    public double add(double a, double b) throws RemoteException {
        System.out.println("执行加法: " + a + " + " + b);
        return a + b;
    }
    
    @Override
    public double subtract(double a, double b) throws RemoteException {
        System.out.println("执行减法: " + a + " - " + b);
        return a - b;
    }
    
    @Override
    public double multiply(double a, double b) throws RemoteException {
        System.out.println("执行乘法: " + a + " * " + b);
        return a * b;
    }
    
    @Override
    public double divide(double a, double b) throws RemoteException {
        if (b == 0) {
            throw new RemoteException("除数不能为零");
        }
        System.out.println("执行除法: " + a + " / " + b);
        return a / b;
    }
}

3. 服务器端

// CalculatorServer.java
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

public class CalculatorServer {
    public static void main(String[] args) {
        try {
            // 创建RMI注册表,端口1099
            LocateRegistry.createRegistry(1099);
            System.out.println("RMI注册表已启动");
            
            // 创建远程对象
            Calculator calculator = new CalculatorImpl();
            
            // 将远程对象绑定到注册表
            Naming.rebind("rmi://localhost:1099/CalculatorService", calculator);
            System.out.println("计算器服务已注册");
            System.out.println("服务器正在运行...");
            
        } catch (Exception e) {
            System.err.println("服务器异常: " + e.toString());
            e.printStackTrace();
        }
    }
}

4. 客户端

// CalculatorClient.java
import java.rmi.Naming;
import java.util.Scanner;

public class CalculatorClient {
    public static void main(String[] args) {
        try {
            // 查找远程对象
            Calculator calculator = (Calculator) Naming.lookup("rmi://localhost:1099/CalculatorService");
            System.out.println("成功连接到计算器服务");
            
            Scanner scanner = new Scanner(System.in);
            
            while (true) {
                System.out.println("\n=== 计算器菜单 ===");
                System.out.println("1. 加法");
                System.out.println("2. 减法");
                System.out.println("3. 乘法");
                System.out.println("4. 除法");
                System.out.println("0. 退出");
                System.out.print("请选择操作: ");
                
                int choice = scanner.nextInt();
                
                if (choice == 0) {
                    break;
                }
                
                System.out.print("请输入第一个数字: ");
                double a = scanner.nextDouble();
                System.out.print("请输入第二个数字: ");
                double b = scanner.nextDouble();
                
                double result = 0;
                switch (choice) {
                    case 1:
                        result = calculator.add(a, b);
                        break;
                    case 2:
                        result = calculator.subtract(a, b);
                        break;
                    case 3:
                        result = calculator.multiply(a, b);
                        break;
                    case 4:
                        try {
                            result = calculator.divide(a, b);
                        } catch (Exception e) {
                            System.out.println("错误: " + e.getMessage());
                            continue;
                        }
                        break;
                    default:
                        System.out.println("无效的选择");
                        continue;
                }
                
                System.out.println("结果: " + result);
            }
            
            scanner.close();
            System.out.println("客户端已退出");
            
        } catch (Exception e) {
            System.err.println("客户端异常: " + e.toString());
            e.printStackTrace();
        }
    }
}

编译和运行步骤

1. 编译所有文件

javac *.java

2. 启动RMI注册表(在单独的命令行窗口)

rmiregistry

3. 启动服务器(在另一个命令行窗口)

java CalculatorServer

4. 运行客户端(在第三个命令行窗口)

java CalculatorClient

更复杂的示例:支持回调的聊天服务

远程接口

// ChatService.java
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ChatService extends Remote {
    void registerClient(ChatClient client) throws RemoteException;
    void sendMessage(String message) throws RemoteException;
    void unregisterClient(ChatClient client) throws RemoteException;
}

// ChatClient.java
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ChatClient extends Remote {
    void receiveMessage(String message) throws RemoteException;
    String getClientName() throws RemoteException;
}

RMI 的优势和限制

优势:

1、简单易用,Java原生支持

2、自动处理对象序列化

3、支持分布式垃圾回收

4、类型安全

限制:

1、仅支持Java-to-Java通信

2、防火墙穿透能力有限

3、性能可能不如其他RPC框架

4、安全性需要考虑

RMI为Java应用程序提供了强大的分布式计算能力,特别适合纯Java环境的分布式系统开发。

最后更新于6月前
本文由人工编写,AI优化,转载请注明原文地址: java.rmi使用方法及代码示例

评论 (7)

登录 后发表评论

陈小莎陈小莎2025-11-27 11:52:30

非常清晰的RMI教程!示例代码很实用,让我终于理解了远程接口和实现的关系。感谢作者分享!

小确幸小确幸2025-11-24 12:05:15

感谢作者分享这么详细的Java RMI教程!原理和代码示例都很清晰,让我对远程方法调用的流程有了直观的理解。请问在实际项目中,RMI和Web服务该如何选择?

管理员管理员2025-11-24 20:06:20

在绝大多数现代项目中,应优先选择 Web 服务(特别是基于 HTTP/REST 和 JSON 的 API)。RMI 仅适用于非常特定的、高性能的、且完全处于 Java 技术栈内部的场景。

林小兔林小兔2025-11-21 08:54:40

非常清晰的RMI教程!代码示例很实用,让我对远程方法调用的流程一目了然。感谢作者的分享!

程同学程同学2025-11-13 10:28:08

感谢作者分享!示例代码很清晰,让我对RMI的组件和流程有了直观的理解。请问在实际项目中,如何处理RMI调用的超时和重试机制呢?

管理员管理员2025-11-24 20:05:31

Java RMI的实际项目中,可以通过System.setProperty设置连接和读取超时时间,可以自定义重试机制,例如重试策略接口、RMI服务调用器等。

露娜Luna露娜Luna2025-11-08 11:06:50

最近正好在做一个分布式计算项目,用到了RMI。这个指南的代码示例很清晰,帮我解决了服务注册表连接超时的问题,感谢分享!