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

Java 分布式計算核心技術:RMI 遠程調用原理、實戰代碼與 Jini 服務發現演進

     編輯:Java 相關知識

前言

當業務邏輯跨越多台機器、多個 JVM 時,如何像調用本地方法一樣透明地調用遠程對象?Java RMI (Remote Method Invocation) 給出了標準答案。本文深度解析 RMI 架構(Stub/Skeleton、Registry、序列化協議),提供完整可運行的「Hello World」級服務端/客戶端代碼,並延伸介紹 Jini 的自適應發現與自我修復機制。

RMI 核心架構四大角色

  1. Remote Interface:繼承 java.rmi.Remote,聲明拋 RemoteException 的業務方法,作為客戶端與服務端的契約。
  2. Remote Implementation:實現業務邏輯,通常繼承 UnicastRemoteObject 獲得遠程能力(自動導出、監聽端口)。
  3. Stub (Client Helper):客戶端代理,封裝網絡通訊細節(序列化參數、發送請求、接收結果/異常),外觀與 Remote Interface 一致。
  4. Skeleton (Server Helper):服務端接收請求、反序列化、調用真實實現、序列化返回。JDK 1.2+ 內建,無需顯式生成。

RMI 架構圖

完整代碼實戰

1. 遠程接口 MyRemote.java

package com.dennisit.rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface MyRemote extends Remote {
    String sayHello() throws RemoteException;
}

2. 服務實現 MyRemoteImpl.java

package com.dennisit.rmi;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
    protected MyRemoteImpl() throws RemoteException { super(); }

    @Override
    public String sayHello() {
        return "server says, rmi hello world !";
    }

    public static void main(String[] args) {
        try {
            MyRemote service = new MyRemoteImpl();
            // 綁定到 RMI Registry:rmi://host:port/name
            Naming.rebind("rmi://127.0.0.1/Remote Hello World", service);
            System.out.println("Service bound and ready.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3. 客戶端 MyRemoteClient.java

package com.dennisit.rmi;

import java.rmi.Naming;

public class MyRemoteClient {
    public void exec() {
        try {
            MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/Remote Hello World");
            System.out.println(service.sayHello());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new MyRemoteClient().exec();
    }
}

部署與運行步驟

  1. 編譯:javac *.java
  2. 生成 Stub/Skeleton(JDK 1.5+ 可跳過,動態代理):rmic com.dennisit.rmi.MyRemoteImpl
  3. 啟動 RMI Registry:在類路徑下執行 rmiregistry(默認端口 1099)。
  4. 啟動服務端:java -Djava.rmi.server.codebase=file:./ com.dennisit.rmi.MyRemoteImpl
  5. 啟動客戶端:java com.dennisit.rmi.MyRemoteClient

運行截圖

關鍵注意事項(避坑指南)

  • 參數/返回值必須實現 Serializable:否則運行時拋 MarshalException,編譯期不報錯。
  • Registry 必須先啟動:Naming.rebind 依賴 Registry 存活。
  • Stub 類必須分發給客戶端:若不使用動態代理(JDK 1.5+ 默認開啟),需將 _Stub.class 打包到客戶端 classpath。
  • 防火牆/網絡隔離:RMI 使用隨機高端口進行實際數據傳輸,需配置 java.rmi.server.hostname 或使用 RMISocketFactory 固定端口範圍。
  • 安全策略:若啟用 SecurityManager,需授予 SocketPermission。

從 RMI 到 Jini:服務發現的演進

特性RMI RegistryJini Lookup Service
查找鍵字符串名稱(如 "Remote Hello World")服務接口類型(如 ScientificCalculator.class)
發現機制客戶端必須知晓 Registry IP/端口IP 組播自動發現 Lookup Service,無需硬編碼地址
服務註冊手動 rebind服務啟動自動尋找 Lookup Service 註冊,攜帶序列化代理(Stub/驅動/服務本體)
租約機制無有:服務定期續約,失效自動剔除,實現「自我修復網絡」
適用場景靜態拓撲、內部 RPC動態部署、設備即插即用、服務網格雛形

企業級演進:EJB 容器與現代微服務

RMI 是 EJB 遠程調用的底層協議;現代微服務多採用 HTTP/REST、gRPC、Dubbo 等更高層級框架,但理解 RMI 的序列化、代理、註冊發現模型,對排查分布式調用超時、類加載衝突、版本不兼容等疑難雜症極有幫助。

總結

Java RMI 以「接口為契約、Stub/Skeleton 透明代理、Registry 服務發現」三大支柱,實現了跨 JVM 的方法調用透明化。掌握 UnicastRemoteObject 導出、Naming.rebind/lookup 註冊發現、序列化約束、動態 Stub 生成機制,即可構建健壯的分布式 Java 服務。Jini 在此基礎上引入組播發現與租約機制,為後來的服務註冊中心(Eureka、Consul、Nacos)奠定了概念基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved