先前所介紹的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
            
      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、資料庫或相關儲存媒介。

