首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java RMI 實戰教程:從網絡通信原理到分布式告警系統完整代碼

     編輯:Java 相關知識

前言:RMI 在分布式架構中的定位

RMI (Remote Method Invocation) 是 Java 原生分布式 RPC 框架,EJB 的基石。雖然 gRPC、Dubbo、Spring Cloud 等現代框架更主流,但理解 RMI 有助於掌握「接口與實現分離」、「存根/骨架」、「註冊中心」等分布式核心概念。本文結合中國移動自動撥測系統實戰案例,完整演示 RMI 服務端、客戶端、接口定義、啟動流程與網絡原理。

網絡通信底層原理回顧

所有分布式通信本質:基於傳輸協議 (TCP/HTTP) + 網絡 IO (BIO/NIO/AIO) 將字節流從一台機器傳到另一台。RMI 底層使用 JRMP (Java Remote Method Protocol) 協議,基於 TCP Socket,默認序列化機制為 Java 原生序列化。

RMI 開發五步曲

  1. 定義遠程接口(繼承 Remote,方法拋 RemoteException);
  2. 實現遠程接口(繼承 UnicastRemoteObject);
  3. 啟動 RMI Registry 並綁定遠程對象(Naming.bind);
  4. 客戶端查找遠程對象(Naming.lookup)並調用;
  5. 分別啟動服務端與客戶端驗證。

業務場景:撥測系統實時告警推送

流程:設備告警 → RMI Client → RMI Server → 業務處理接口 → 入庫 → Web/GIS 實時展示。
接口契約:int interactive(int funIndex, String param),param 為 key=value&key=value 格式,funIndex=1 表示設備告警。

完整代碼實現

1. 遠程接口

package nbpt.ts.manager.message.service;
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface RmiMonitorService extends Remote {
    int interactive(int funIndex, String param) throws RemoteException;
}

2. 服務端實現

package nbpt.ts.manager.message.service.impl;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import nbpt.ts.manager.message.service.RmiMonitorService;
import nbpt.ts.manager.message.service.WarnService;

public class RmiMonitorServiceImpl extends UnicastRemoteObject implements RmiMonitorService {
    private static final long serialVersionUID = -3771656108378649574L;
    public static final int SUCCESS = 1, FAIL = 0;
    private WarnService warnService;

    public RmiMonitorServiceImpl() throws RemoteException { super(); }

    @Override
    public int interactive(int funIndex, String param) throws RemoteException {
        int result = FAIL;
        if (funIndex == 1) { // 設備告警
            warnService = new WarnServiceImpl(); // 實際從 Spring 獲取
            warnService.dealWarn(param);
            result = SUCCESS;
        }
        return result;
    }
    // Getter/Setter for Spring 注入
}

3. 服務啟動類(綁定註冊中心)

package nbpt.ts.manager.message.service;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import nbpt.ts.manager.message.service.impl.RmiMonitorServiceImpl;

public class RmiServer {
    private String ip = "localhost";
    private int port = 8889;

    public void init() {
        try {
            LocateRegistry.createRegistry(port); // 啟動內嵌 Registry
            RmiMonitorService service = new RmiMonitorServiceImpl();
            Naming.bind("//" + ip + ":" + port + "/comm", service);
            System.out.println("RMI 服務啟動成功:" + ip + ":" + port);
        } catch (RemoteException | AlreadyBoundException | MalformedURLException e) {
            e.printStackTrace();
        }
    }
    // Getter/Setter for Spring 配置
    public static void main(String[] args) { new RmiServer().init(); }
}

4. 客戶端調用

package nbpt.ts.manager.message.service;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class MonitorClient {
    private String ip = "localhost";
    private int port = 8889;
    private RmiMonitorService monitorService;

    public int interactive(int funIndex, String param) {
        try {
            getMonitorService().interactive(funIndex, param);
            return 1;
        } catch (RemoteException e) { e.printStackTrace(); return 0; }
    }

    private RmiMonitorService getMonitorService() {
        if (monitorService == null) {
            try {
                monitorService = (RmiMonitorService) Naming.lookup("rmi://" + ip + ":" + port + "/comm");
            } catch (NotBoundException | MalformedURLException | RemoteException e) { e.printStackTrace(); }
        }
        return monitorService;
    }

    public static void main(String[] args) {
        MonitorClient client = new MonitorClient();
        String msg = "tsid=1022&devid=10001027&warnid=102&warntype=01&warnlevel=1&warnmsg=設備出錯,請檢查。";
        client.interactive(1, msg);
    }
}

5. 業務接口與實現

// WarnService.java
public interface WarnService { int dealWarn(String message); }

// WarnServiceImpl.java
public class WarnServiceImpl implements WarnService {
    @Override public int dealWarn(String message) {
        System.out.println("已接收網絡告警:" + message);
        // 解析入庫、推送 WebSocket 等
        return 1;
    }
}

關鍵技術點解析

  • UnicastRemoteObject:導出遠程對象,監聽匿名端口接收調用,提供存根;
  • LocateRegistry.createRegistry:JVM 內嵌註冊中心,避免單獨啟動 rmiregistry;
  • Naming.bind vs rebind:bind 重複拋異常,rebind 覆蓋,生產建議 rebind;
  • 序列化版本:serialVersionUID 必須顯式聲明,防止反序列化失敗;
  • 防火牆/NAT:RMI 回調端口隨機,跨網段需配置 java.rmi.server.hostname 或使用 HTTP 隧道/代理模式。

現代化替代方案對比

總結

RMI 雖屬「古典」技術,但其「接口驅動、存根代理、註冊發現」思想貫穿現代 RPC 體系。掌握 RMI 完整流程,能為學習 gRPC、Dubbo 打下堅實基礎。生產新項目建議優先選型成熟微服務框架,舊系統維護時本文代碼可直接參考。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
框架協議序列化服務發現適用場景
RMIJRMP (TCP)Java 原生RMI Registry純 Java 內部調用、教學、舊系統維護
HessianHTTPHessian 二進制無/自建跨語言、防火牆友好、輕量
Web Service (JAX-WS)HTTP/SOAPXMLUDDI/WSDL企業級異構集成、標準化要求高
gRPCHTTP/2ProtobufConsul/Etcd/K8s微服務、高性能、多語言、流式
Dubbo/Spring CloudTCP/HTTPHessian/Protobuf/JSONZookeeper/Nacos/Eureka國產微服務生態、治理豐富