提及JavaEE開發,絕大多數人都去選擇Spring這一系列的框架,很少會直接選擇EJB方面的東西(具體歷史遺留方面的問題可以自己查閱),所以說JSF,CDI等系列的東西學的人也就少了,所以這裏開始講解一些關於CDI的一些用法,具體可參照官方給出的文檔(最新已到2.0版本).
CDI UserGuide:
這裏寫鏈接內容
1.基本注入@Inject
字段,構造方法,方法體
2.瞬態注入@Inject Instance myInstances;
當把一個依賴bean注入到一個長期存在的bean時,後者初始化時(@Inject)這個注入完成並只執行一次。
如果我想每次訪問時都再次初始化並且重新注入時必須這樣寫:
@Inject Instance<MyBean> myBeanInstances;
public Mybean getMyBean() { return myBeanInstances.get(); }
而在CDI組的一個開發者,說希望CDI2.0變成
//現在還不是這樣
@Inject @Transient MyBean myBean;
Bean 通常是一個包含業務邏輯的應用程序類。它可直接從 Java 代碼中,調用或通過統一 EL 可能會調用它。Bean 可以訪問事務性資源。Bean 之間的依賴關係由容器自動管理。大多數Bean是有狀態和上下文。Bean 的生命週期是由容器進行管理。
第二方面,上下文真正意味着什麼.由於一些Bean是有狀態的.我們會有一個Bean實例.不同於無狀態的組件模型(如EJB stateless session beans.)或一個單例組件模型(如servlet或單例bean),不同的用戶用到/看到不同的Bean,然而,像一個無狀態或單例模式,與有狀態會話bean不同,客戶端不控制實例的生命週期去顯式地創建和銷燬它。
相反,該 bean 的範圍確定:生命週期的每個 bean 的實例和哪些客戶端共享對該 bean 的特定實例的引用。
對於給定的線程在 CDI 應用程序中,可能與 bean 的範圍關聯活動上下文。這種情況下可能是唯一的線程 (例如,如果該 bean 是request scoped),或它可能與某些其他線程共享 (例如,如果該 bean 是session scoped),甚至其他所有線程 (如果它是application scoped)。客戶端(例如,其他bean)執行相同的上下文將看到相同的bean的實例。
Bean types, qualifiers and dependency injection
要注入的Bean需要滿足的條件是:
a bean type,
a set of qualifiers.
public classBookShopextendsBusinessimplementsShop<Book> {
...
}
上面代碼的類型爲BookShop ,Business ,Shop以及Object.
下面EJB的類型爲:Business ,Shop以及Object.
@Stateful
public class BookShopBean extends Business implements BookShop, Auditable {
...
}
不是BookShop 類型是因爲這個EJB不是客戶端可見的Bean.
但是Bean可以顯示的使用CDI註解 @TYPE 來指定Bean type.如下code:
@Typed(Shop.class)
public class BookShop extends Business implements Shop<Book> {
...
}
那麼這個Bean的類型就限定爲Shop,Object
有時,一個bean類型本身並沒有提供足夠的信息去知道到底哪個bean注入了容器。
例如,假設我們有兩個PaymentProcessor接口的實現:CreditCardPaymentProcessor,DebitPaymentProcessor。
注入一個字段類型是PaymentProcessor的Bean將是不靠譜的,它會屬於一種歧義類型.
在這些情況下,客戶端必須重新進行明確的指定.
這時,我們可以使用CDI限定符註解:@Qualifier.它主要用來消除歧義類型.
如下,我們定義一個Qualifier:
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface CreditCard {}
接着,我們這樣使用.
@CreditCard
public classCreditCardPaymentProcessorimplementsPaymentProcessor{
...
}
我們已經定義了一個限定符註解,以及對CreditCardPaymentProcessor 進行了限定符的使用.我們可以使用它來消除歧義的注入點。如:
@Inject @CreditCard PaymentProcessor paymentProcessor
這就回到我們的開始說的,要注入的Bean需要滿足的條件是:
a bean type,
a set of qualifiers.
注:
如果一個bean或注射點不明確指定一個限定詞,他會有一個默認的限定詞,就是@Default.
這只是簡單的一種情況,後續還有其他情況的處理.慢慢來,不急.
更多詳細參加後續文章.
Scope
bean定義了生命週期的範圍和實例的可見性。CDI上下文模型是可擴展的,適應任意範圍。然而,某些重要的範圍是內置在規範,容器進行提供(如RequestScope,SessionScope,ConversationScope,applicationScope等)。
如下面的例子.
public @SessionScoped classShoppingCartimplementsSerializable{
...
}
請注意:一旦使用SessionScope,是沒辦法在上下文中手動刪除Bean.除非上下文被銷燬.
這種情況請考慮使用RequsetScope或ConversationScope.
如果未顯式指定一個範圍,然後該bean屬於特殊的範圍稱爲dependent pseudo-scope(依賴僞範圍).如該bean被注入到SessionScope裏,那該bean就是SessionScope.
更多詳細參加後續文章.
EL Name
@Named 註釋只是能夠讓頁面使用EL,沒有其他功能.最常見的就是JSF視圖通過EL引用某個bean。
public @SessionScoped @Named("cart")classShoppingCartimplementsSerializable{ ... }
在JSF/JSP頁面中如下使用:
<h:dataTablevalue="#{cart.lineItems}"var="item">
...
</h:dataTable>
如果@Named(“cart”)後面沒有寫(“cart”),那默認值就是shoppingCart.
頁面爲:
<h:dataTablevalue="#{shoppingCart.lineItems}"var="item">
...
</h:dataTable>
Alternatives
我們已經看到在開發時限定符如何讓我們一個接口選擇多個實現。但有時我們有一個接口(或其他bean類型)的實現會根據部署環境的變化而變化。
public @Alternative classMockPaymentProcessorextendsPaymentProcessorImpl{ ... }
因此就會用到@Alternatives,在Bean.xml裏進行相關的配置指定。具體後續再講。
Interceptors
這個就暫時不講,等後續有專門章節進行講述。
2. What kinds of classes are beans?
- ManagedBean
- sessionBean(EJB Session Bean)
(就是EJB相關Bean,但不是消息驅動Bean和JPA實體,這2個非上下文對象,不能被注入的其他對象,但能注入其他對象,使用CDI其他功能。)
需要使用EJB的情況如下:
方法級別的事務管理和安全,
併發管理
有狀態會話bean的實例級鈍化
無狀態會話bean實例池
遠程或 web 服務調用
計時器和異步方法
3.Producer methods
Producer方法通過@Produces和定義quarfiler使用。
import javax.enterprise.inject.Produces;
@ApplicationScoped
public classRandomNumberGenerator{
private java.util.Random random = new java.util.Random(System.currentTimeMillis());
@Produces @Named @Random intgetRandomNumber(){
return random.nextInt(100);
}
}
在其他頁面調用:
@Inject @Random int randomNumber;
在JSF頁面EL表達式爲:
<p>Your raffle number is #{randomNumber}.</p>
這個是簡單的應用,後續會有更詳細說明。
4.Producer fields
這個可以說是Producer methods的簡化版。具體待以後講解。本章就先說到這裏。