SeamFramework.orgCommunity Documentation

章 5. Scope 與 context

5.1. Scope type
5.2. 內建 scope
5.3. conversation scope
5.3.1. Conversation demarcation(對話區分)
5.3.2. Conversation propagation(傳播)
5.3.3. Conversation timeout(逾時)
5.4. dependent pseudo-scope
5.4.1. @New 標記

到目前為止,我們已見過了一些 scope 類型標記(scope type annotations)的範例了。Web Bean 的 scope 可決定 Web Bean instance 的生命週期(lifecycle)。Scope 也能決定哪個客戶端參照哪個 Web Bean 的 instance。根據 Web Bean 規格,scope 可決定:

  • 任何含有該 scope 的 Web Bean 的新 instance 應何時被建立

  • 任何含有該 scope 的 Web Bean 的現有 instance 應何時被刪除

  • 哪個被注入的參照代表含有該 scope 的 Web Bean 的任何 instance

比方說若我們有個 session scope 的 Web Bean CurrentUser,那麼所有在相同 HttpSession 的 context 中被調用的 Web Bean 都會看見相同的 CurrentUser 的 instance。當 CurrentUser 在該 session 中第一次被需要時,這個 instance 就會自動地被建立,並且在這個 session 結束時被自動地刪除掉。

Web Bean 含有著一個 extensible context model(可延伸的 context 模型)。您可藉由建立新的 scope 類型標記來定義新的 scope:

@Retention(RUNTIME)

@Target({TYPE, METHOD})
@ScopeType
public @interface ClusterScoped {}

當然,那是這項工作中最簡單的部份。若要此 scope 類型能被有效使用,我們還需要定義一個能夠實做該 scope 的 Context 物件!實做一個 Context 通常是一項非常技術性的工作,這只應使用於架構開發(framework development)上。

我們可套用一個 scope 類型標記至一個 Web Bean 實做 class 來指定 Web Bean 的 scope:

@ClusterScoped

public class SecondLevelCache { ... }

您通常會使用到其中一個 Web Bean 的內建 scope。

Web Bean 定義了四個內建的 scope:

使用 Web Bean 的網站應用程式:

請求和應用程式 scope 在下列情況中會是有效的:

若應用程式嘗試透過一個沒有有效 context 的 scope 來引動 Web Bean 的話,Web Bean 管理員便會在 runtime 時回傳一項 ContextNotActiveException

四個內建 scope 中有其中的三個對於所有 Java EE 開發人員來說應該都不陌生,所以我們將不花時間在此討論它們。不過在這之中有個 scope 則是新的。

Web Bean 的 conversation scope 和傳統的 session scope 類似,它們都持有著有關於系統用戶的狀態,並發出多重請求至伺服器。conversation scope 和 session scope 不同的地方在於:

Conversation(對話)代表一項工作,從用戶角度來看是項工作的單位。conversation 的 context 持有和用戶目前工作相關的狀態。若用戶同時間一次進行多項工作的話,那就會有多個 conversation。

conversation context 會在任何 JSF 請求進行中的時候啟用。不過,大部分的 conversation 都會在請求結束後被刪除掉。若有個 conversation 必須持有多重請求的狀態,它便需要被明確地轉為 long-running conversation

Web Bean 提供了一個內建的 Web Bean,它可被用來在 JSF 應用程式中控制 conversation 的生命週期。這個 Web Bean 能透過注入下列來取得:

@Current Conversation conversation;

若要將和目前的請求關聯的 conversation 轉為 long-running conversation 的話,請由應用程式的程式碼調用 begin() method。若要將目前的 long-running conversation context 排程在目前請求結束時被刪除,請調用 end()

在下列範例中,有個 conversation-scoped 的 Web Bean 會控制和它關聯的 conversation:

@ConversationScoped @Stateful

public class OrderBuilder {
    private Order order;
    private @Current Conversation conversation;
    private @PersistenceContext(type=EXTENDED) EntityManager em;
    
    @Produces public Order getOrder() {
        return order;
    }
    public Order createOrder() {
        order = new Order();
        conversation.begin();
        return order;
    }
    
    public void addLineItem(Product product, int quantity) {
        order.add( new LineItem(product, quantity) );
    }
    public void saveOrder(Order order) {
        em.persist(order);
        conversation.end();
    }
    
    @Remove
    public void destroy() {}
    
}

這個 Web Bean 能夠透過使用 Conversation API 來控制它自己的生命週期。不過有些其它 Web Bean 的生命週期完全取決於另一個物件。

除了這四個內建的 scope,Web Bean 還提供了一項稱為 dependent pseudo-scope 的功能。這是個未明確宣告 scope 類型的 Web Bean 的預設 scope。

比方說,這個 Web Bean 的 scope 類型為 @Dependent

public class Calculator { ... }

當 Web Bean 的一個注入點解析至一個相依 Web Bean 時,每當第一個 Web Bean 被例示(instantiate)時,相依 Web Bean 的一個新的 instance 就會被建立。相依 Web Bean 的 instance 絕不會被共享於不同的 Web Bean 或不同的注入點之間。它們是其它 Web Bean instance 的 dependent object(相依物件)

相依 Web Bean 的 instance 會在它們所依賴的 instance 被刪除掉時跟著被一起刪除。

Web Bean 使得取得 Java class 或是 EJB bean 的相依 instance 變得相當容易,儘管該 class 或是 EJB bean 已被宣告為一個含有其牠 scope 類型的 Web Bean。