1. 簡介
Session Bean 是目前 EJB 規格 (EJB 2.0) 中 3種 Enterprise Bean 的其中一種,另外兩種分別是 Entity Bean 和 Message Driven Bean,這3種 Enterprise Bean 依照其特性被應用在不同的範疇中。其中 Session Bean 和 Entity Bean 早在 EJB 1.x 規格中就已經存在,Message Driven Bean 卻是在 EJB 2.0 才被加入。
在 EJB 架構中,Session Bean 主要目的是塑造企業流程,當中可能包括系統運算、存取資料庫、呼叫其他 Enterprise Bean等等。其範例包括流程引擎、買賣交易、型錄查詢等應用。接下來會從 Session Bean 的各個不同的特性說明其實際應用的方式、時機和要注意的地方。
2. Stateless & Stateful Session Bean
在 EJB 規格中,Session Bean被細分為 Stateless Session Bean 和 Stateful Session Bean。兩者根據特性在應用上有著很大差異:
與客戶端之間的對話資訊
Session Bean 不能被共用,每一個 Bean 只能用來服務一個客戶,而 Bean 和客戶端之間會有一份對話資訊 (請參考附註 [A] )。
●Stateless Session Bean
基本上只在單一方法呼叫中保存對話資訊,一旦 Bean 完成處理後,對話資訊會隨著被清除。
●Stateful Session Bean
在同一個 Session 裡,可以保留呼叫者與 Session Bean 之間的對話資訊與狀態,等下一次執行方法時繼續提供使用。
生命週期
Session Bean 的生命週期除了依不同廠商的 EJB Container 會有所不同外,Bean 的 Stateful 特性也會影響到其存活的時機。
●Stateless Session Bean
當客戶端所呼叫 Stateless Session Bean完畢後,Bean 會馬上被 EJB Container 銷毀,或將實例 (Instance) 保存下來以供其他客戶端使用。
●Stateful Session Bean
和 Stateless Session Bean 不同,當客戶端所呼叫Stateless Session Bean完畢後,Bean 不會馬上被 EJB Container 銷毀,而是繼續存在於 Session Bean Pool (請參考附註 [B] ),直到 Session 完結。
使用時機
●Stateless Session Bean
1. 不需要在每次客戶端對 Session Bean 的方法呼叫後保持對話資訊。
●Stateful Session Bean
1. 在每個 Session Bean 的方法呼叫之間需要保持 Session 中的資訊。
2. 利用 Session Bean 的對話狀態 (Conversational State) (請參考附錄) 管理企業流程。
效能
●Stateless Session Bean
由於不需要管理對話資訊,也就是可以佔用比較少系統資源去暫存與客戶端之間的對話資訊,而且在每次被呼叫完畢後可以馬上轉移給其他客戶端使用,故效能較佳。
●Stateful Session Bean
每次被客戶端呼叫完畢後都會將代表這客戶端的狀態資訊暫時儲存起來,在 Session 完畢後也要把之前所記錄與客戶端的對話資訊清除,所以會消耗較多系統資源。
3. 開發 Session Bean
開發一支 Session Bean 時,至少包括4個步驟:
1. 編寫 Home Interface
2. 編寫 Remote Interface
3. 編寫 Bean 的實作 (Implement) 類別,當中包括描述企業流程的方法實作
4. 編寫部署文件 (ejb-jar.xml)
編寫 Home 介面
Session Bean 的`介面繼承自 javax.ejb.EJBHome,負責控制一個 Session Bean 的生命週期,含有建立與銷毀 EJB 物件的方法,一般情況下,其命名規則為 <<Bean-name>> + Home。要注意的是,Home介面中需要定義一個 create() 方法 (對應到 Bean 實作類別的 ejbCreate()),用來取得一個 Bean 的實例。另外 Home 介面中也可以定義一個 remove() 方法對應到 Bean 實作類別的 ejbRemove()),用來移除 Bean 的實例。
【範例】
package examples;
import javax.ejb.*;
import java.rmi.RemoteException;
public Interface HelloWorldHome extends EJBHome{
HelloWorld create() throws RemoteExcception, CreateException;
}
編寫 Remote介面
繼承自 javax.ejb.EJBObject,含有 Bean 裡所有的每一個方法以供遠端程序呼叫,一段情況下,其命名規則為 <<Bean-name>>。由於遠端介面是 RMI-IIOP 遠端介面 (繼承 java.rmi.Remote) ,因此必須拋出 java.rmi.RemoteException。
【範例】
package examples;
import javax.ejb.*;
import java.rmi.RemoteException;
public Interface HelloWorld extends EJBObject{
public void helloWorld() throws RemoteException;
}
編寫 Session Bean 的實作類別
繼承自 javax.ejb.SessionBean,一段情況下,其命名規則為 <<Bean-name>> + Bean。定義一個 Session Bean 可以透過定義一個實現 javax.ejb.SessionBean 介面的類別來達成,該介面定義如下:
public Interface javax.ejb.SessionBean extends javax.ejb.EnterpriseBean{
public void ejbCreate(…) throws RemoteException;
public void ejbActivate() throws RemoteException;
public void ejbPassivate() throws RemoteException;
public void ejbRemove() throws RemoteException;
public void setSessionContext(SessionContext ctx) throws RemoteException;
}
以上幾個方法並不是要讓客戶端使用和呼叫的,而是要讓 EJB Container 使用來管理 Session Bean 的生命週期,因此不可以直接在客戶端程式裡呼叫。每個方法的說明如下,詳細的方法呼叫時機請參考「Session Bean 與 EJB Container 互動」:
方法
|
說明
|
ejbCreate(…)
|
初始化 Session Bean
|
ejbActivate()
|
EJB container 將 Session Bean 主動化 (activate) 後馬上呼叫此一方法,取得 Bean 所需資源 (在 stateless 不需實作,因為不需維護對話資訊)
|
ejbPassivate()
|
EJB container 將 Session Bean 被動化 (passivate) 後馬上呼叫此一方法,釋放 Bean 所佔的資源(如 socket 連線)
|
ejbRemove()
|
EJB container 將 Session Bean 從記憶體中移除之前會呼叫此一方法,釋放所有已配置的資源
|
setSessionContext(SessionContext ctx)
|
EJB container 將 Session Bean 與 Session Context 關聯在一起,Bean 可以從中查詢目前交易狀態和資訊
|
【範例】
package examples;
import javax.ejb.*;
public Interface HelloWorldBean extends EJBObject{
public void helloWorld(){
System.out.println(“Hello Word !!!”);
}
public void ejbCreate() throws CreateException{
System.out.println(“ejbCreate”);
}
public void ejbRemove() {
System.out.println(“ejbRemove”);
}
public void ejbActivate() {
System.out.println(“ejbActivate”);
}
public void ejbPassivate() {
System.out.println(“ejbPassivate”);
}
public void setSessionContext(SessionContext ctx) {
System.out.println(“setSessionContext”);
}
}
編寫部署文件 ejb-jar.xml
要讓所編寫的 Session Bean 可以在 EJB Container 部署和正確運作,除了編寫程式碼外,我們還需要把 Session Bean 的特性描述在部署文件,也就是 ejb-jar.xml。編寫 Session Bean 時,不需要在程式碼中指明所寫的 Bean 是 stateless 還是 stateful,其 stateful 特性是定義在部署文件裡,也就是說可以透過修改部署文件而簡單的把 Session Bean 在 stateless 和 stateful 之間切換。
【範例】
<!DOCTYPE ejb-jar PUBLIC
“-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN”
“http://java.sun.com/dtd/ejb-jar_2_0.dtd”>
<ejb-jar>
<enterprise-Beans>
<Session>
<ejb-name>Hello</ejb-name>
<Home>examples.HelloWorldHome</Home>
<remote>examples.HelloWorld</ remote>
<ejb-class>examples.HelloWorldBean</ejb-class>
<Session-type>Stateless</Session-type>
<transaction-type>Container</transaction-type>
</Session>
</enterprise-Beans>
</ejb-jar>
<ejb-name>
|
Session Bean 的名稱
|
<Home>
|
Session Bean 的 Home 介面
|
<remote>
|
Session Bean 的 remote 介面
|
<ejb-class>
|
Session Bean 實作的類別
|
<Session-type>
|
描述Session Bean 的 stateful 特性 (Stateless / Stateful)
|
<transaction-type>
|
描述 Session Bean 的交易特性 (Container / Bean)
|
4. Session Bean 與 EJB Container 互動
在客戶端的程式呼叫 Session Bean 的方法時,其實 Bean 會根據其特性 (stateful 特性) 和 EJB container 互動,以下簡單的說明 EJB container 如何管理 Session Bean 的生命週期。
Stateless Session Bean
1. 當客戶端程式呼叫 Stateless Session Bean 上的方法之前,會先呼叫 Bean 的Home 介面中的create() 以取得一個 Bean 的參考 (reference)。
2. EJB container 會馬上呼叫 ejbCreate() 和 setSessionContext() 產生一個 Bean 實例和把 Session Context 和 Bean 關聯在一起。
3. 當方法呼叫完畢,EJB container 會呼叫 ejbRemove() 把 Bean 銷毀,Bean 所佔用的資源也會被釋放。
Stateful Session Bean
1. 和 Stateless Session Bean 一樣,客戶端程式呼叫 Stateful Session Bean 上的方法之前會先呼叫 create() 取得一個 Bean 的參考。
2. EJB container 會馬上呼叫 ejbCreate() 和 setSessionContext() 產生一個 Bean 實例和把 Session Context 和 Bean 關聯在一起。
3. 由於 Stateful Session Bean 會管理與客戶端之間的對話資訊,所以在Bean 的方法被呼叫完畢後,EJB container 不會馬上把 Bean 銷毀,而是在適當時間 (依不同廠商的EJB Container 會有所不同) 把 Bean 被動化 (呼叫 ejbPassivate()) 和將對話資訊暫存起來。
4. 當客戶端程式再次呼叫 Bean 上的方法時,如果 Bean 是在被動狀態,EJB container 會呼叫 Bean 的 ejbActivate() 把 Bean 的狀態轉為預備狀態,而之前暫存的對話資訊也會再放進 Bean 實例裡。
5. 當客戶端程式呼叫 Bean 的 remove() 或是客戶端的 Session 已經完結時,EJB container會呼叫 ejbRemove() 把 Bean 銷毀,Bean 所佔用的資源也會被釋放,之前所保持的與客戶端之間的對話資訊也會同時被清除。
附註 [A] 對話資訊:包括 Session 資訊和對話狀態 Conversational State。當客戶端程式呼叫 Session Bean 時,可能會改變其實例參數 (Instance Variable) 的值。在客戶端程式再次呼叫同一個 Session Bean 參考的方法時,Stateful Session Bean 會保留上次方法呼叫被改變的實例參數的值,但 Stateless Session Bean 卻不會。
附註 [B] Session Bean Pool:EJB container 存放 Session Bean 實例 (Instance) 的地方,可根據不同的需要而設定大小 (設定於佈署文件中),Pool 的大小會影響系統效能。