在 EJB 架構中,Enterprise Bean 需要一個管道來獲取運行時環境資訊、管理事務邊界以及執行安全檢查。這個管道就是 EJB Context。容器為每個 Bean 實例提供一個 Context 物件,封裝了 Bean 生命週期所需的上下文資訊,主要包含四大類:
Context 物件在 Bean 的生命週期中可能會變更,容器負責注入最新的狀態。根據 Bean 類型不同,Context 介面分為 SessionContext(會話 Bean)與 EntityContext(實體 Bean),兩者皆繼承自 javax.ejb.EJBContext。
EJB 1.0 定義的 EJBContext 介面提供了基礎操作:
public interface javax.ejb.EJBContext {
public javax.ejb.EJBHome getEJBHome();
public java.util.Properties getEnvironment();
public java.security.Identity getCallerIdentity();
public boolean isCallerInRole(java.security.Identity role);
public javax.jts.UserTransaction getUserTransaction();
public void setRollbackOnly();
public boolean getRollbackOnly();
}
SessionContext 繼承並擴充了 getEJBObject() 方法,這對於「Bean 作為另一個 Bean 的客戶端」場景至關重要。因為 Bean 不能直接傳遞 this 參考給外部(所有呼叫必須透過 EJB 物件代理),必須透過 getEJBObject() 取得遠端介面引用才能傳遞給其他 Bean。
EJB 安全模型分為兩個階段:
EJB 規範未強制規定鑑別實作方式,各應用伺服器(如 WebLogic)通常在 JNDI InitialContext 建立時傳入 Principal 與 Credentials:
Properties props = System.getProperties();
props.put(Context.SECURITY_PRINCIPAL, "EmployeeA");
props.put(Context.SECURITY_CREDENTIALS, "myPassWord1");
Context ctx = new InitialContext(props);
進階伺服器支援整合 LDAP、Windows 域等現有身分管理系統。
授權分為宣告式與程式化兩種模式:
SecurityException。
<AccessControlEntries>
submitPurchaseOrder [employees]
approvePurchaseOrder [managers]
DEFAULT [administrators]
</AccessControlEntries>
// 檢查角色
Identity adminRole = new MyIdentity("administrators");
if (ctx.isCallerInRole(adminRole)) { /* 管理員邏輯 */ }
// 獲取呼叫者身分
Identity caller = ctx.getCallerIdentity();
String name = caller.getName();
對於需要跨越客戶端會話斷線、重連場景(如購物車、長時間流程),EJB 提供 Handle 機制。Handle 是 EJB 物件的序列化代理,可持久化至資料庫或檔案系統,後續可還原為 EJB 物件繼續呼叫,且會話狀態不丟失:
// 取得 Handle 並序列化儲存
javax.ejb.Handle handle = myEJBObject.getHandle();
ObjectOutputStream out = ...;
out.writeObject(handle);
// 反序列化並還原 EJB 物件
ObjectInputStream in = ...;
Handle restoredHandle = (Handle) in.readObject();
MyRemoteInterface ejbObj = (MyRemoteInterface) restoredHandle.getEJBObject();
ejbObj.callMethod(); // 繼續業務呼叫
此機制對有狀態會話 Bean 尤為重要,確保會話狀態在客戶端離線期間得以保全。