使用 Stateful Session Bean


先前所介紹的Session Bean為Stateless,也就是Session Bean本身不因操作而處於特定狀態,當容器啟動後,Stateless Session Bean建立後會被容器放入池(Pool)中,若有客戶端需要時從池中取出,用畢後歸還池中。

若客戶端的操作分作數個步驟,而操作的過程中需要保留Session Bean的狀態,則可以使用@Stateful標示Session Bean為Stateful Session Bean,Stateful Session Bean與客戶端為一對一的關係,每個客戶端請求時,會話階段期間會配置專屬的Stateful Session Bean,直到客戶端離開(Stateful Session Bean的有效期間結束),或是呼叫了標示為@Remove的方法後,將Stateful Session Bean摧毀回收資源。

以下先使用一個簡單的範例,示範如何使用Stateful Session Bean,首先定義服務介面:
  • HelloBean.java
package onlyfun.caterpillar;

import javax.ejb.Remote;

@Remote
public interface HelloBean {
public String doStep1(String data);
public String doStep2(String data);
public String finish(String data);
}

介面中定義三個方法,模擬客戶端完成某個任務時共需三個步驟,而實作類別如下:
  • HelloBeanImpl.java
package onlyfun.caterpillar;

import javax.ejb.Remove;
import javax.ejb.Stateful;

@Stateful(name="ejb/HelloFacade")
public class HelloBeanImpl implements HelloBean {
private String step;
public String doStep1(String data) {
step = data + "processedByStep1/";
return step;
}

public String doStep2(String data) {
step = step + data + "processedByStep2/";
return step;
}

@Remove
public String finish(String data) {
step = step + data + "processedByFinish";
return step;
}
}

@Stateful標示這是個Stateful Session Bean,它擁有特定的狀態,程式中使用step成員來模擬,建議Stateful Session Bean必須使用@Remove標示一個方法,表明該方法被呼叫後,容器將可以催毀該Stateful Session Bean而回收資源。

在客戶端的部份,使用以下的程式來模擬:
  • Main.java
package onlyfun.caterpillar;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;

public class Main {
public static void main(String[] args) throws NamingException {
InitialContext context = new InitialContext();
Object obj = context.lookup("onlyfun.caterpillar.HelloBean");
HelloBean hello = (HelloBean) PortableRemoteObject.narrow(
obj, HelloBean.class);

String result = hello.doStep1("data1");
System.out.println(result);

result = hello.doStep2("data2");
System.out.println(result);

result = hello.finish("finishData");
System.out.println(result);
}
}

在程式中,呼叫hello的doStep1()、doStep2()來模擬完成某個操作的幾個步驟,容器端將維護與客戶端的會話階段,保留操作過程中的Session Bean狀態,而最後呼叫finish()方法後,會話完成而回收Session Bean。

程式中還需要的jndi.properties,請參考 第 一個 Session Bean(單機客戶端) 中的內容。

一個執行的結果如下所示:
data1processedByStep1/
data1processedByStep1/data2processedByStep2/
data1processedByStep1/data2processedByStep2/finishDataprocessedByFinish

基本上,不建議使用Stateful Session Bean,Stateful Session Bean會為每個客戶端維護一個實例,一但容器判斷系統資源耗用太多,就會作Passivate,將Bean作序列化以儲存在實體媒介,若需要時再作Activate的動作,將已儲存的Bean反序列化,這些都會是效能上的負擔。

建議使用Stateful Session Bean一定要標示@Remove的方法,並在不使用Stateful Session Bean時明確呼叫該方法,讓容器可以回收資源,可以的話,思考是否可用Stateless Session Bean,若需要特定狀態時,可以考慮將之儲存在HttpSession、資料庫或相關儲存媒介。