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

漫談 EJB 之 RMI-IIOP 與 JNDI 核心基礎設施深度解析 (系列二):遠程接口、Stub/Skeleton、對象序列化、命名服務

     編輯:Java 相關知識

EJB 兩大基石:RMI-IIOP (通訊) + JNDI (查找)

EJB 容器之所以能提供透明的遠程調用、負載均衡、故障轉移、安全傳播,核心依賴於 RMI-IIOP 協議棧與 JNDI 命名服務。本文深度剖析 RMI-IIOP 遠程接口設計、Stub/Skeleton 代理機制、對象序列化傳遞語義、JNDI Context 體系與 EJB 客戶端查找流程。

RMI-IIOP:Java 分布式對象模型的標準化實現

遠程接口設計規範 (java.rmi.Remote)

public interface MyRemote extends Remote {
    // 1. 必須拋出 RemoteException (或父類 Exception)
    // 2. 參數/返回值: 基本類型、Serializable、Remote 接口
    // 3. 方法簽名不可為 final/static (接口默認 public abstract)
    String process(Request req) throws RemoteException, BusinessException;
    
    // 返回遠程對象引用 (傳遞 Stub)
    OtherService getService() throws RemoteException;
}

遠程對象實現:兩種導出方式

// 方式一: 繼承 UnicastRemoteObject (自動導出,綁定匿名端口)
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
    public MyRemoteImpl() throws RemoteException { super(); }
    // ... 實現方法
}

// 方式二: 不繼承 (需繼承其他類),手動導出
public class MyRemoteImpl extends SomeBaseClass implements MyRemote {
    public MyRemoteImpl() throws RemoteException {
        // 導出對象,可指定端口、Socket 工廠
        UnicastRemoteObject.exportObject(this, 0); // 0=匿名端口
    }
    // ... 實現方法
    // 取消導出: UnicastRemoteObject.unexportObject(this, true);
}

Stub/Skeleton 代理架構:實現「本地/遠程透明」

Client JVM                          Server JVM
┌─────────────────┐                 ┌─────────────────┐
│  Client Code    │                 │  Remote Impl    │
│  myRemote.do()  │                 │  do()           │
└────────┬────────┘                 └────────┬────────┘
         │                                   │
         ▼                                   ▼
┌─────────────────┐                 ┌─────────────────┐
│  Stub (Proxy)   │  JRMP/IIOP      │  Skeleton       │
│  - 連接管理     │ ◄─────────────► │  - 反序列化參數 │
│  - 參數序列化   │   網絡傳輸      │  - 分發調用實現 │
│  - 等待響應     │                 │  - 序列化結果   │
│  - 反序列化結果 │                 └─────────────────┘
└─────────────────┘
         │
         ▼
   Return Value
  • Stub:客戶端代理,實現遠程接口,負責網絡通訊細節。**JDK 1.2+ 動態生成 (動態代理),無需 rmic 預編譯**,但舊容器/特定協議 (IIOP) 仍需預生成 _Stub.class。
  • Skeleton:服務端分發器。**JDK 1.2+ 內置於反射調用機制中,無獨立類**。
  • 生成工具:rmic -iiop MyRemoteImpl (生成 IIOP Stub/Tie),rmic -v1.2 MyRemoteImpl (生成 JRMP Stub)。

對象序列化與參數傳遞語義

對象類型傳遞方式序列化機制遠程端修改影響
基本類型按值直接寫入流無影響
實現 Serializable按值 (深度複製)ObjectOutputStream (默認) / Externalizable (自定義)修改副本,不影響源
實現 Remote按引用傳遞 Stub 參考調用路由回源端,**影響源**
既 Serializable 又 Remote按引用 (Remote 優先)傳遞 Stub影響源

序列化關鍵點

  • serialVersionUID:強烈建議顯式聲明,避免版本不匹配導致 InvalidClassException。
  • transient:標記字段不參與序列化 (如密碼、連接句柄、緩存)。
  • Externalizable:完全控制讀寫格式 (writeExternal/readExternal),性能優於默認序列化。
  • RMI 類加載:Stub 反序列化時若本地無類,從 java.rmi.server.codebase (HTTP/FTP) 下載,**需 SecurityManager 允許**。

JNDI:統一命名與目錄訪問 API

核心概念體系

  • Context:目錄節點接口,提供 lookup, bind, list, createSubcontext 等操作。
  • InitialContext:入口點,構造時讀取環境屬性 (java.naming.factory.initial, provider.url) 確定具體 SPI 實現 (LDAP, CORBA, RMI, DNS, File)。
  • Name:複合名稱 (CompositeName) 或複合名稱 (CompoundName),支持層級路徑 java:comp/env/jdbc/MyDB。
  • Reference / ObjectFactory:存儲對象構造信息 (類名、工廠類、屬性),查找時由工廠動態創建實例 (如 DataSource)。

JNDI 在 EJB 中的關鍵角色

  1. EJB Home 綁定:部署時容器將 Home Stub 綁定到 JNDI (如 ejb/MyBean)。
  2. 客戶端查找:
    Context ctx = new InitialContext(props);
    Object ref = ctx.lookup("ejb/MyBean");
    MyBeanHome home = (MyBeanHome) PortableRemoteObject.narrow(ref, MyBeanHome.class);
  3. 資源引用:java:comp/env/jdbc/MyDB (DataSource), java:comp/env/jms/MyQueue (JMS), java:comp/env/mail/MyMail (JavaMail)。
  4. 環境屬性:env-entry 注入配置值 (String, Integer, Boolean 等)。

Context 環境屬性速查

屬性常量字符串鍵說明
Context.INITIAL_CONTEXT_FACTORYjava.naming.factory.initialSPI 實現類全限定名
Context.PROVIDER_URLjava.naming.provider.url服務端點 URL
Context.SECURITY_PRINCIPALjava.naming.security.principal用戶名
Context.SECURITY_CREDENTIALSjava.naming.security.credentials密碼
Context.URL_PKG_PREFIXESjava.naming.factory.url.pkgsURL 上下文工廠包前綴

RMI-IIOP + JNDI 協同工作流程 (EJB 客戶端視角)

  1. 客戶端構造 InitialContext (指定 IIOP 工廠 + Provider URL)。
  2. lookup("ejb/MyBean") 發起 CORBA/IIOP 查找請求到命名服務 (CosNaming)。
  3. 命名服務返回 Home Interface **Stub (IOR)**。
  4. 客戶端 PortableRemoteObject.narrow() 縮窄轉型為 Home 接口代理。
  5. 調用 home.create() → Stub 發送 IIOP 請求 → 服務端 Skeleton/Tie 分發 → 容器創建 EJB 實例/從池獲取 → 返回 EJBObject Stub。
  6. 客戶端持有 EJBObject Stub,後續業務方法調用走相同 IIOP 路徑。
  7. 容器管理事務/安全/並發上下文通過 IIOP **Service Context** 隱式傳播。

總結

RMI-IIOP 提供了**標準化的遠程對象調用協議棧** (接口、Stub/Skeleton、序列化、JRMP/IIOP),JNDI 提供了**統一的命名查找抽象層** (Context、SPI、Reference)。二者結合,構成了 EJB 透明分布式、容器管理服務、異構互操作的基礎設施。掌握遠程接口規範、序列化語義、Stub 代理機制、JNDI 環境配置,是排查 EJB 通訊失敗、ClassCastException、序列化異常、查找超時等疑難雜症的關鍵。

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