CDI基礎入門之Beans解析

提及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?

  1. ManagedBean
  2. 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的簡化版。具體待以後講解。本章就先說到這裏。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章