傳統 RMI(遠程方法調用)要求客戶端預先知道服務提供者的完整 URL(如 rmi://host:port/ServiceName),這造成了部署與維護的不便。Jini 技術則透過發現機制讓客戶端無需知曉服務位置,自動獲取服務代理。本文將展示如何為現有 RMI 系統實現一套類 Jini 的發現機制,使客戶端擺脫硬編碼 URL 的束縛。
雖然 Jini 提供完整的服務發現框架,但許多企業已擁有大量基於 RMI 的成熟系統。在 Jini 成為主流前,為這些系統提供優雅的遷移路徑具有現實意義。本文目標是為 RMI 服務器賦予類 Jini 的發現能力,同時保持其獨立運行特性。
客戶端必須指定服務位置:
Translator service = (Translator) Naming.lookup("rmi://theHost/SpanishTranslator");
客戶端透過 ServiceDiscoveryManager 依介面類型查找服務,無需指定位置:
Class[] classes = new Class[]{Translator.class};
ServiceTemplate tmpl = new ServiceTemplate(null, classes, null);
ServiceDiscoveryManager mgr = new ServiceDiscoveryManager(null, null);
ServiceItem item = mgr.lookup(tmpl, null);
Translator service = (Translator) item.service;
Jini 模型的核心優勢在於位置透明化——客戶端不需關心服務部署在何處。
Translator service = (Translator) RMIDiscovery.lookup(Translator.class, "Spanish");
其中 clazz 為服務介面,id 為區分同介面不同實例的唯一標識。
借鑑 Jini 發現機制:
ServerSocket 監聽單播回應。| 服務端動作 | 客戶端動作 |
|---|---|
| 在多播地址啟動監聽 | 建立 ServerSocket 監聽單播回應 |
| 解析收到的 UDP 封包,若有效則單播連回客戶端 | 向多播地址發送 UDP 查詢封包 |
| 序列化並發送遠程 Stub | 從輸入流讀取遠程對象 |
| 關閉連線 | 關閉 ServerSocket,停止發送多播,開始使用服務 |
客戶端指定 介面類別 + 唯一 ID 來識別目標服務實例,支援多實例並行部署。服務端每個 RMI 服務器即充當自身的查找服務,無需獨立註冊中心。
下篇將深入實作細節,包括多播監聽器、單播分發器、Stub 傳輸與安全性考量。