EJB 遠程調用涉及 RMI、JNDI、Stub/Skeleton、容器生成類等核心機制。本文基於 WebLogic 實現,詳細拆解從客戶端 JNDI 查找到 Bean 方法執行的完整呼叫鏈路,釐清 10 個類文件的角色與生成時機。
| 角色 | 類名稱 | 來源 |
|---|---|---|
| Bean 類 | HelloBean | 用戶編寫 |
| Bean WebLogic 實現類 | HelloBean_Impl | ejbc 編譯生成 |
| Remote 介面 | Hello | 用戶編寫 |
| Remote WL 實現類 | HelloBean_EOImpl | ejbc 生成 |
| Remote WL Stub | HelloBean_EOImpl_WLStub | 部署時動態生成位元碼 |
| Remote WL Skeleton | HelloBean_EOImpl_WLSkeleton | 部署時動態生成位元碼 |
| Home 介面 | HelloHome | 用戶編寫 |
| Home WL 實現類 | HelloBean_HomeImpl | ejbc 生成 |
| Home WL Stub | HelloBean_HomeImpl_WLStub | 部署時動態生成位元碼 |
| Home WL Skeleton | HelloBean_HomeImpl_WLSkeleton | 部署時動態生成位元碼 |
關鍵差異: RMI 需客戶端預備 Stub 類,EJB 由伺服器動態傳送 Stub 實例,客戶端僅需介面類(Hello.class, HelloHome.class)。
ctx.lookup("Hello") → JNDI 查找。HelloBean_HomeImpl_WLStub 實例,序列化傳回。home(實為 Home Stub),調用 home.create()。HelloBean_HomeImpl.create()。HelloBean_HomeImpl.create() → 調用 HelloBean_Impl.ejbCreate() 創建 Bean 實例。HelloBean_EOImpl_WLStub 實例,序列化傳回客戶端。Hello h = home.create()(實為 Remote Stub)。h.helloWorld() → 實際調用 HelloBean_EOImpl_WLStub.helloWorld()。HelloBean_EOImpl_WLSkeleton 接收 → 調用 HelloBean_EOImpl.helloWorld()。HelloBean_EOImpl 轉調用 HelloBean_Impl.helloWorld() → 最終執行用戶編寫的 HelloBean.helloWorld()。_Impl 類由 ejbc 靜態生成,Stub/Skeleton 由容器運行時動態生成(WebLogic 特有)。// 客戶端代碼
HelloHome home = (HelloHome) PortableRemoteObject.narrow(ctx.lookup("Hello"), HelloHome.class);
Hello h = home.create();
h.helloWorld();
// 實際運行對象
home.toString() → "HelloBean_HomeImpl_WLStub@18c458"
h.toString() → "HelloBean_EOImpl_WLStub@8fa0d1"
雖代碼操作介面,實際操作的是 Stub 實例。介面僅為編譯期契約。
EJB 遠程調用本質是 兩次完整的 RMI 循環:第一次獲取 Home 代理並創建 Bean,第二次獲取 Remote 代理並執行業務邏輯。WebLogic 通過 ejbc 預生成實現類、部署時動態生成 Stub/Skeleton,實現了開發簡單(僅寫 3 個介面/類)與運行時分散式透明的平衡。