SeamFramework.orgCommunity Documentation
到目前為止,我們已見過了一些 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:
@RequestScoped
@SessionScoped
@ApplicationScoped
@ConversationScoped
使用 Web Bean 的網站應用程式:
任何 servlet 請求都可存取 active request、session 和應用程式 scope,另外
任何 JSF 請求也都能存取一個現行的 conversation scope。
請求和應用程式 scope 在下列情況中會是有效的:
當調用 EJB 的遠端 method 時、
當 EJB 逾時時、
當訊息傳送給訊息導向的 bean 時,以及
當進行網路服務調用時。
若應用程式嘗試透過一個沒有有效 context 的 scope 來引動 Web Bean 的話,Web Bean 管理員便會在 runtime 時回傳一項 ContextNotActiveException
。
四個內建 scope 中有其中的三個對於所有 Java EE 開發人員來說應該都不陌生,所以我們將不花時間在此討論它們。不過在這之中有個 scope 則是新的。
Web Bean 的 conversation scope 和傳統的 session scope 類似,它們都持有著有關於系統用戶的狀態,並發出多重請求至伺服器。conversation scope 和 session scope 不同的地方在於:
conversation scope 已被應用程式明確區分,並且
它在 JSF 應用程式中會持有和特定網站瀏覽器分頁相關的狀態。
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 的生命週期完全取決於另一個物件。
conversation context 會隨著任何 JSF face 的請求(JSF form submission)自動地傳播。它不會隨著 non-face 的請求(例如透過連結來瀏覽)自動地傳播。
我們能夠透過包含 conversation 的唯一識別碼(unique identifier)來作為一個請求參數以強制 conversation 隨著 non-face 的請求進行傳播。Web Bean 規格保留了一個名為 cid
的請求參數以用於此情況下。conversation 的唯一識別碼可藉由 Conversation
這個物件取得,並且它的 Web Bean 名稱為 conversation
。
因此,下列連結會傳播 conversation:
<a href="/addProduct.jsp?cid=#{conversation.id}" >Add Product</a >
Web Bean 管理員也必須將 conversation 在任何重定向作業之間進行傳播,儘管該 conversation 沒有被標記為 long-running。這使得實做一般的 POST-then-redirect 模式變得非常簡單,這樣便無須使用一些像是「flash」物件的脆弱 construct。在此情況下,Web Bean 管理員會自動地新增一個請求參數至重定向 URL。
Web Bean 管理員能夠隨時隨地刪除它 context 中的 conversation 以及所有狀態以保留資源。一個 Web Bean 管理員實做一般會利用某種形式的 timeout 來這麼作 儘管這在 Web Bean 規格中是非必要的。Timeout 代表 conversation 在被刪除之前所經過的休止狀態時間。
Conversation
這個物件提供了一個能設置 timeout 的 method。這是個給 Web Bean 管理員的提示,您可忽略該設定。
conversation.setTimeout(timeoutInMillis);
除了這四個內建的 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。
內建的 @New
綁定標記允許在注入點能夠有暗示性的相依 Web Bean 定義。假設我們宣告下列被注入的欄位:
@New Calculator calculator;
如此一來有個含有 scope @Dependent
、綁定類型 @New
、API 類型 Calculator
、實做 class Calculator
以及建置類型 @Standard
的 Web Bean 就被暗示性地定義了。
就算 Calculator
已經被宣告為不同 scope type,這還是有效的,比方說:
@ConversationScoped
public class Calculator { ... }
因此下列已注入的屬性都會各得到一個 Calculator
的不同 instance:
public class PaymentCalc {
@Current Calculator calculator;
@New Calculator newCalculator;
}
calculator
這個欄位中注入了一個 Calculator
的 conversation-scoped instance。newCalculator
欄位中有個新的 Calculator
的 instance 被注入了,並且它的生命週期取決於擁有它的 PaymentCalc
。
這項功能對於 producer method 來講特別有幫助,我們將在下個章節中討論到。