實體 Bean 是 EJB 規範中負責映射持久化數據 (通常為關係數據庫表行) 的核心組件。在 BEA WebLogic Server 8.1 環境下,本文系統闡述從設計決策、代碼生成、打包部署到性能優化的完整實踐指南。
| 對比項 | CMP (容器管理持久化) | BMP (Bean 管理持久化) |
|---|---|---|
| 可移植性 | 高 (無特定 SQL,跨數據庫) | 低 (硬編碼 SQL/JDBC) |
| 開發維護 | 簡單 (聲明式映射) | 複雜 (手寫 ejbLoad/Store/JDBC) |
| 性能 | 優 (容器生成優化 SQL、批次操作) | 依賴開發者技巧 |
| 關係導航 | 原生支持 CMR (本地接口) | 手動管理外鍵查詢 |
| 適用場景 | 90%+ 標準 CRUD 業務 | 複雜存儲過程、非標準數據源、舊系統遷移 |
決策建議:默認選 CMP。僅當存在極複雜的多表關聯邏輯、存儲過程調用、或非關係數據源時考慮 BMP。
EntityBean、EntityLocalHome、EntityLocal、EntityHome、Entity,部署描述符聲明両者。早期 EJB 1.x 僅支持遠程接口,細粒度實體導致網絡調用爆炸 (N+1 問題),故推薦粗粒度。EJB 2.0 引入**本地接口**,消除了進程內調用開銷,使「一個表一個實體 Bean」的細粒度設計成為可能:
order.getItems()。爭議提示:部分專家仍主張粗粒度 (DTO 聚合) 以減少數據庫往返。建議根據具體業務驗證,WebLogic 8.1 CMP 引擎對細粒度優化極佳。
getXxx() (抽象方法)。setXxxWrapper() 包裝器 → 內部調用 setXxx() + 驗證邏輯。ValueObject (DTO) 類,包含所有需傳輸字段。getData() 返回 DTO,updateData(DTO) 批量更新。AccountEJB.jar
├── META-INF/
│ ├── ejb-jar.xml # 標準部署描述符 (EJB 2.0 規範)
│ ├── weblogic-ejb-jar.xml # WebLogic 專用 (事務、緩存、池、安全等)
│ └── weblogic-cmp-rdbms-jar.xml # CMP 專用 (表映射、字段映射、關係、查詢)
├── com/example/ejb/
│ ├── AccountBean.class # 實現類 (實現 EntityBean)
│ ├── AccountHome.class # 遠程 Home 接口
│ ├── Account.class # 遠程 Component 接口
│ ├── AccountLocalHome.class # 本地 Home 接口
│ ├── AccountLocal.class # 本地 Component 接口
│ └── AccountPK.class # 主鍵類 (復合主鍵時必需)
└── ... (輔助類可選內置或獨立 JAR)
WebLogic 8.1 SP02+ 內置 ejbgen.jar,僅需編寫 **Bean 實現類 + 標註**,自動生成所有接口、主鍵類、三個 XML 描述符。
# 設置 Classpath
set CLASSPATH=%WL_HOME%\server\lib\ejbgen.jar;%CLASSPATH%
# 執行生成 (基於 Javadoc Doclet 機制)
javadoc -docletpath ejbgen.jar -doclet weblogic.tools.ejbgen.EJBGen AccountBean.java
/**
* @ejb:bean name="AccountEJB"
* type="CMP"
* primkey-field="accountId"
* jndi-name="ejb/AccountEJB"
* local-jndi-name="ejb/AccountLocalEJB"
* @ejb:finder signature="java.util.Collection findByCustomerId(long customerId)"
* query="SELECT OBJECT(o) FROM AccountEJB o WHERE o.customerId = ?1"
* @ejb:persist-field name="accountId" type="long" prim-key="true"
* @ejb:persist-field name="balance" type="double"
* @ejb:persist-field name="currency" type="String"
* @ejb:relation name="Account-Owner"
* target-ejb="CustomerEJB"
* multiplicity="many-to-one"
* @weblogic:resource-ref res-ref-name="jdbc/BankDB" jndi-name="jdbc/BankDB"
*/
public abstract class AccountBean implements EntityBean {
// 抽象 CMP 字段 Getter/Setter
public abstract long getAccountId();
public abstract void setAccountId(long id);
public abstract double getBalance();
public abstract void setBalance(double balance);
// ... ejbCreate/PostCreate, ejbRemove, ejbLoad/Store 等回調可選實現
}
-d <dir>:生成類/接口輸出目錄。-descriptorDir <dir>:生成 XML 描述符輸出目錄。jar 打包部署。Required, RequiresNew 等)、CMR 關係定義、查詢方法 (EJB QL)。cache-type (LRU/NRU), max-beans-in-cache。initial-beans-in-free-pool, max-beans-in-free-pool。concurrency-strategy (Exclusive/Database/ReadOnly/Optimistic)。transaction-isolation (ReadCommitted/Serializable 等)。delay-database-insert-until (ejbCreate/ejbPostCreate)。table-map (Bean -> Table, 主鍵生成策略)。field-map (CMP 字段 -> Column, SQL 類型)。relationship-role-map (外鍵列、級聯刪除)。weblogic-ql / sql-shape (複雜 JOIN、存儲過程調用)。automatic-key-generation (Oracle Sequence, SQL Server Identity, Named Sequence Table)。| 優化點 | 配置位置 | 推薦值/策略 |
|---|---|---|
| 並發策略 | weblogic-ejb-jar.xml | 只讀/高讀少寫 -> ReadOnly (定時刷新) 或 Optimistic (版本列);高寫 -> Database (依賴 DB 鎖) |
| 關係緩存 | weblogic-cmp-rdbms-jar.xml | relationship-caching 預加載關聯集合,避免 N+1 |
| 批次操作 | weblogic-ejb-jar.xml | enable-batch-operations="true" 合併 INSERT/UPDATE/DELETE |
| 主鍵生成 | weblogic-cmp-rdbms-jar.xml | Oracle -> SEQUENCE;SQL Server -> IDENTITY;通用 -> NAMED_SEQUENCE_TABLE |
| 延遲插入 | weblogic-ejb-jar.xml | delay-database-insert-until="ejbPostCreate" 合併創建與關係設置 |
WebLogic 8.1 實體 EJB 開發的核心在於:**堅定選擇 CMP + 本地接口 + 細粒度領域模型**,利用 EJBGen 消除樣板代碼,通過三層描述符精細控制容器行為。掌握並發策略、關係緩存、批次操作等容器級優化參數,比手寫 SQL 優化更具杠桿效應。遷移至 EJB 3.0/JPA 時,這些概念直接映射為 @Entity, @Table, @OneToMany, @Cacheable, @BatchSize 等註解,架構思想一脈相承。