Java RMI远程方法调用:从入门到精通完整教程
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环境的分布式系统开发。
推荐阅读
评论 (7)
请 登录 后发表评论
非常清晰的RMI教程!示例代码很实用,让我终于理解了远程接口和实现的关系。感谢作者分享!
感谢作者分享这么详细的Java RMI教程!原理和代码示例都很清晰,让我对远程方法调用的流程有了直观的理解。请问在实际项目中,RMI和Web服务该如何选择?
在绝大多数现代项目中,应优先选择 Web 服务(特别是基于 HTTP/REST 和 JSON 的 API)。RMI 仅适用于非常特定的、高性能的、且完全处于 Java 技术栈内部的场景。
非常清晰的RMI教程!代码示例很实用,让我对远程方法调用的流程一目了然。感谢作者的分享!
感谢作者分享!示例代码很清晰,让我对RMI的组件和流程有了直观的理解。请问在实际项目中,如何处理RMI调用的超时和重试机制呢?
Java RMI的实际项目中,可以通过System.setProperty设置连接和读取超时时间,可以自定义重试机制,例如重试策略接口、RMI服务调用器等。
最近正好在做一个分布式计算项目,用到了RMI。这个指南的代码示例很清晰,帮我解决了服务注册表连接超时的问题,感谢分享!