常見誤區
許多開發者誤以為:有狀態 = 實例長期存在保存狀態;無狀態 = 每次調用新建實例。事實恰好相反,本質區別在於生命週期與用戶綁定方式。
核心概念:用戶
Session Bean 的「用戶」是直接調用 EJB 的類實例(或其方法)。同一類的不同實例 = 不同用戶。
有狀態 Session Bean (Stateful)
- 專屬實例:每個用戶擁有專屬 Bean 實例。
- 生命週期綁定用戶:用戶存活期間 Bean 保持狀態(即「有狀態」);用戶消亡(調用結束或實例銷毀),Bean 隨之銷毀。
- 每次獲取均為初始狀態:新用戶獲得全新初始化的 Bean。
無狀態 Session Bean (Stateless)
- 實例池共享:Bean 實例化後放入池中,所有用戶共用。
- 生命週期獨立於用戶:用戶消亡不代表 Bean 銷毀,池中實例可服務下一用戶。
- 無用戶專屬狀態:因無特定用戶,無法保持會話狀態,故稱「無狀態」。
- 實例變量風險:若 Bean 定義非靜態屬性,該屬性將被所有調用者共享修改,極易產生併發 Bug,實務中應避免或加同步。
對比總結表
| 維度 | 有狀態 | 無狀態 |
| 實例歸屬 | 用戶專屬 | 池化共享 |
| 狀態保持 | 跨調用保持 | 不保持(實例變量除外) |
| 生命週期 | 隨用戶創建/銷毀 | 容器管理池化 |
| 適用場景 | 購物車、多步驟流程 | 單次業務操作、高併發服務 |
最佳實踐建議
- 無狀態 Bean 嚴禁 定義可變實例字段,若需共享資料改用 ThreadLocal 或外部快取。
- 有狀態 Bean 適合會話式交互,但需注意併發存取限制(EJB 規範禁止併發調用同一 Stateful Bean)。
- 選型原則:預設優先無狀態,僅在確需會話狀態時使用有狀態。