ToB企服应用市场:ToB评测及商务社交产业平台

标题: Java RMI技术详解与案例分析 [打印本页]

作者: 盛世宏图    时间: 2024-8-5 13:26
标题: Java RMI技术详解与案例分析
Java RMI(Remote Method Invocation)是一种允许Java虚拟机之间进行通信和交互的技术。它使得远程Java对象能够像当地对象一样被访问和操纵,从而简化了分布式应用程序的开发。一些应用依然会使用 RMI 来实现通信和交互,本日的内容我们来聊聊 RMI 的那些事儿。
一、先来相识一下概念

RMI原理

RMI的基本思想是远程方法调用。客户端调用远程方法时,实际上是发送一个调用请求到服务器,由服务器实行该方法,并将效果返回给客户端。RMI通过存根(Stub)和骨架(Skeleton)类来实现远程调用,存根位于客户端,而骨架位于服务器端。
RMI组件

数据通报

RMI使用Java序列化机制来通报数据。客户端将方法参数序列化后通过网络发送给服务器,服务器反序列化参数并实行远程方法,然后将效果序列化回传给客户端。
RMI案例

以下是一个简单的RMI案例,包罗服务器和客户端的实现思路,下文V 将再用代码来表明:
服务器端

客户端

RMI的局限性

RMI的应用场景

RMI适用于需要Java程序之间进行远程通信的场景,如分布式银行系统、游戏服务器、股票买卖业务系统和网上商城等。接下来一起看一个简单的案例使用吧。
二、案例使用

先来搞一个简单的Java RMI服务器端和客户端的实现案例。这个案例中,服务器端将提供一个名为HelloWorld的远程服务,客户端将调用这个服务并打印返回的问候语。
服务器端实现

  1. import java.rmi.Remote;
  2. import java.rmi.RemoteException;
  3. public interface HelloWorld extends Remote {
  4.     String sayHello() throws RemoteException;
  5. }
复制代码
  1. import java.rmi.server.UnicastRemoteObject;
  2. import java.rmi.RemoteException;
  3. public class HelloWorldImpl extends UnicastRemoteObject implements HelloWorld {
  4.     protected HelloWorldImpl() throws RemoteException {
  5.         super();
  6.     }
  7.     @Override
  8.     public String sayHello() throws RemoteException {
  9.         return "Hello, World!";
  10.     }
  11. }
复制代码
  1. import java.rmi.Naming;
  2. import java.rmi.RemoteException;
  3. import java.rmi.registry.LocateRegistry;
  4. public class HelloWorldServer {
  5.     public static void main(String[] args) {
  6.         try {
  7.             // 创建远程对象
  8.             HelloWorld helloWorld = new HelloWorldImpl();
  9.             // 获取RMI注册表的引用,并在指定端口上创建或获取注册表实例
  10.             LocateRegistry.createRegistry(1099);
  11.             // 将远程对象绑定到RMI注册表中,客户端可以通过这个名字访问远程对象
  12.             Naming.bind("rmi://localhost/HelloWorld", helloWorld);
  13.             System.out.println("HelloWorld RMI object bound");
  14.         } catch (Exception e) {
  15.             System.err.println("Server exception: " + e.toString());
  16.             e.printStackTrace();
  17.         }
  18.     }
  19. }
复制代码
客户端实现

  1. import java.rmi.Naming;
  2. import java.rmi.RemoteException;
  3. public class HelloWorldClient {
  4.     public static void main(String[] args) {
  5.         try {
  6.             // 使用RMI注册表的名字查找远程对象
  7.             HelloWorld helloWorld = (HelloWorld) Naming.lookup("rmi://localhost/HelloWorld");
  8.             // 调用远程方法
  9.             String response = helloWorld.sayHello();
  10.             System.out.println("Response: " + response);
  11.         } catch (Exception e) {
  12.             System.err.println("Client exception: " + e.toString());
  13.             e.printStackTrace();
  14.         }
  15.     }
  16. }
复制代码
来详细表明吧

接下来就可以编译所有类文件,运行服务器端程序,确保RMI注册表已经启动(在某些Java版本中会自动启动),再运行客户端程序,搞定。注意一下哈,由于RMI使用Java序列化机制,因此客户端和服务器的类路径必须一致或兼容。
三、RMI 在分布式银行系统中的应用

接下来V哥要先容业务场景下的应用了,拿在分布式银行系统中来说,我们可以使用RMI来实现不同银行分行之间的通信,例如,实现账户信息的查询、转账等操纵。以下是一个简化的示例,其中包罗两个基本操纵:查询账户余额和实行转账,按步骤一步一步来吧。
步骤1: 定义远程接口

首先,定义一个远程接口BankService,它将被各个分行实现以提供银行服务。
  1. import java.rmi.Remote;
  2. import java.rmi.RemoteException;
  3. public interface BankService extends Remote {
  4.     double getAccountBalance(String accountNumber) throws RemoteException;
  5.     boolean transferFunds(String fromAccount, String toAccount, double amount) throws RemoteException;
  6. }
复制代码
步骤2: 实现远程接口

接下来,实现这个接口来创建远程对象,这个对象将提供实际的银行服务。
  1. import java.rmi.server.UnicastRemoteObject;
  2. import java.rmi.RemoteException;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. public class BankServiceImpl extends UnicastRemoteObject implements BankService {
  6.     private Map<String, Double> accounts = new HashMap<>();
  7.     protected BankServiceImpl() throws RemoteException {
  8.         super();
  9.         // 初始化一些账户信息
  10.         accounts.put("123456789", 5000.00);
  11.         accounts.put("987654321", 1000.00);
  12.     }
  13.     @Override
  14.     public double getAccountBalance(String accountNumber) throws RemoteException {
  15.         return accounts.getOrDefault(accountNumber, 0.00);
  16.     }
  17.     @Override
  18.     public boolean transferFunds(String fromAccount, String toAccount, double amount) throws RemoteException {
  19.         if (accounts.containsKey(fromAccount) && accounts.get(fromAccount) >= amount) {
  20.             accounts.put(fromAccount, accounts.get(fromAccount) - amount);
  21.             accounts.merge(toAccount, amount, Double::sum);
  22.             return true;
  23.         }
  24.         return false;
  25.     }
  26. }
复制代码
步骤3: 设置RMI服务器

服务器端将创建BankService的远程对象实例,并将其绑定到RMI注册表中。
  1. import java.rmi.Naming;
  2. import java.rmi.RemoteException;
  3. import java.rmi.registry.LocateRegistry;
  4. public class BankServer {
  5.     public static void main(String[] args) {
  6.         try {
  7.             LocateRegistry.createRegistry(1099); // 创建RMI注册表
  8.             BankService bankService = new BankServiceImpl();
  9.             Naming.rebind("//localhost/BankService", bankService); // 绑定远程对象
  10.             System.out.println("BankService is ready for use.");
  11.         } catch (Exception e) {
  12.             System.err.println("Server exception: " + e.toString());
  13.             e.printStackTrace();
  14.         }
  15.     }
  16. }
复制代码
步骤4: 实现RMI客户端

客户端将使用RMI注册表的名字来查找远程对象,并调用其方法。
  1. import java.rmi.Naming;
  2. import java.rmi.NotBoundException;
  3. import java.rmi.RemoteException;
  4. public class BankClient {
  5.     public static void main(String[] args) {
  6.         try {
  7.             BankService bankService = (BankService) Naming.lookup("//localhost/BankService");
  8.             System.out.println("Account balance: " + bankService.getAccountBalance("123456789"));
  9.             
  10.             // 执行转账操作
  11.             boolean isTransferSuccess = bankService.transferFunds("123456789", "987654321", 200.00);
  12.             if (isTransferSuccess) {
  13.                 System.out.println("Transfer successful.");
  14.             } else {
  15.                 System.out.println("Transfer failed.");
  16.             }
  17.             
  18.             // 再次查询余额
  19.             System.out.println("New account balance: " + bankService.getAccountBalance("123456789"));
  20.         } catch (RemoteException | NotBoundException e) {
  21.             System.err.println("Client exception: " + e.toString());
  22.             e.printStackTrace();
  23.         }
  24.     }
  25. }
复制代码
来详细表明一下

撸完代码后,编译所有类文件,运行服务器端程序BankServer,再运行客户端程序BankClient,测试效果吧。
末了

末了V哥要提醒一下,在实际的银行系统中,当然还需要思量安全性、事务性、持久性以及错误处理等多方面的因素,RMI的网络通信也需要在安全的网络情况下进行,以防止数据泄露或被篡改。你在应用中是怎么使用 RMI 的,欢迎关注威哥爱编程,一起交换一下哈。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4