請尊重成果,如需轉載請注明來源http://equalxx.iteye.com/
Chapter 2.More about beans關于bean的更多内容
bean一般是包含業務邏輯的應用類。可以直接被java代碼調用,也可以在标準的EL表達式中調用。Bean也可以通路事務資源。Bean之間的依賴關系由容器自動管理,大多bean是有狀态和上下文的。Bean的生命周期由容器管理。
讓我們再看一下,到底什麼叫“有上下文的”?bean有沒有狀态關系到我有哪個bean的執行個體。不像一個沒有狀态的元件模型(比如無狀态會話bean)或是一個單例元件模型(比如servlets或是單例bean),有狀态bean在不同的用戶端有着不同的狀态。是否辨別使用者可見狀态(client-visible state)取決于用戶端有沒有對這個bean的執行個體的引用。
無狀态或單例模型,不同于有狀态會話bean,用戶端不會通過顯式地建立銷毀它來控制它的生命周期。取而代之的是用bean scope來決定:
1、每個bean執行個體的生命周期
2、哪些用戶端可以共享對bean的指定執行個體的引用
對于CDI應用的給定線程,可能會有一個通過bean scope關聯的活動上下文。這個上下文在這個線程中可能是唯一的(比如這個bean是request scoped的),或是它也可能同時與其他線程共享(比如這個bean是session scoped的),甚至和所有其他線程共享(這用的是application scoped)。
執行在同一上下文中的用戶端(比如說其他beans)用的都是同一個bean執行個體。但是在不同上下文中執行的用戶端,用的是不同的執行個體(這取決于上下文之間的關系)。
上下文其中一項最大的優點就是它可以讓狀态bean像service一樣。用戶端不必去管理它的bean的生命周期,也不用知道bean的生命周期是什麼。這些bean都是松耦合的,因為:
1、他們通過明确的公共API來管理互相間關系
2、它們的生命周期跟用戶端完全解耦
我們可以把一個bean替換成繼承同一個接口的另一個bean(這個bean可以有不同的生命周期(scope))而不用影響任何其他bean的實作。事實上,CDI提供了一個簡單的方式在部署時重載,我們會在4.7節的“Alternatives”詳細介紹。
要注意不是所有bean的用戶端都是bean本身。其他對象,比如servlets或消息驅動bean(message-driven beans),他們都不是可注入到其他bean的上下文對象,但他們仍然能夠通過注入擷取對其他bean的引用。
2.1. The anatomy of a bean 對bean的解析
在此前我們已經鋪墊了這麼多,下面我們來正式地介紹bean,根據規範:
一個bean由以下屬性組成:
1、一個(非空)bean類型集
2、一個(非空)限定符集
3、一個Scope
4、可選,一個bean EL name
5、一組攔截器綁定
6、一個bean的實作
此外,一個bean可能是alternativ的,也可能不是。
讓我們去看看這些屬性都是什麼意思。
2.1.1 Bean types,qualifiers and dependency injection bean類型,限定符和依賴注入
Bean通常通過依賴注入擷取對其他bean的引用。任何一個被注入的屬性規定了一個“合同”,所有要注入的bean必須滿足這個“合同”。這個“合同”就是:
1、bean type
2、一組限定符
bean type表明了bean是使用者可見類型,它可以是使用者定義的class或接口。如果bean是個EJB會話bean,那麼它的bean type就是@Local接口,或是bean-class的本地視圖。一個bean可能會有很多個bean type。比如說下面的bean有四個bean type:
public class BookShop
extends Business
implements Shop<Book> {
...
}
它的bean type是 BookShop,Business和Shop<Book>,以及隐式類型java.lang.Object。(注意,參數化類型是合法的bean類型)。
同時,下面這個會話bean隻有本地的三個接口BookShop,Auditable和java.lang.Object可以作為bean type,但由于@Stateful,BookShopBean不是使用者可見類型。
@Stateful
public class BookShopBean
extends Business
implements BookShop, Auditable {
...
}
注意:會話bean的bean type包括本地接口和bean類local view(如果有的話)。EJB遠端接口不被認為是會話bean的bean type。你不能把一個EJB通過遠端接口注入,除非你定義一個資源,這個會在Chapter 14,Java EE元件環境資源中介紹。
(譯者注:其實這段光看英文感覺難以和實際使用關聯起來,bean type到底講了什麼,檢視了一些資料以後我認為可能是在說,bean通過可以通過不同的bean type注入,而bean type包含了什麼内容,有個網址裡面有說明http://moon26.blogspot.jp/2012/01/javaee6-cdi-bean-and-bean-types.html,我會接下來和同僚一起讨論,它究竟在開發中處于什麼角色,再來更新此部分内容)
Bean types可以通過@Typed注解來指定,同時列出所有應該為bean type的類。比如說這個bean types bean已經被限制為Shop<Book>和java.lang.Object:
@Typed(Shop.class)
public class BookShop
extends Business
implements Shop<Book> {
...
}
有時,僅有bean type的話并不能提供給容器足夠的資訊去讓容器知道該注入哪個bean。舉例說,假設我有兩個實作了PaymentProcessor接口的實作類:CreditCardPaymentProcessor和DebitPaymentProcessor。如果把它倆注入到PaymentProcessor類型的域中,就會引起混淆。在這種情況下,使用者必須提供更多的特性來告知容器應該注入哪一個。是以我們通過qualifier來指明特性。
一個qualifier是個使用者定義的注解,用@Qualifier來定義。它是一個類型系統(type system)的一個擴充。它使我們不用基于名稱來區分注入類型。以下就是個用@Qualifier注解的例子:
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface CreditCard {}
你可能還不習慣看到上面這樣的建立注解的代碼,有可能這是你第一次遇到這樣定義。用CDI的話,定義注解将會成為你時不時需要去做的事兒。
注意:
請注意在CDI和EJB中的注解名稱,你會發現他們多是形容詞。我們鼓勵您在建立自定義注解時候也遵循這種習慣,當它們是用來描述行為和指明類角色的時候。
現在我們已經定義了一個特性注解了,我們可以在注入點使用它來明确注入類。下面的注入點包含了bean類型PaymentProcessor以及qualifier @CreditCard:
@Inject @CreditCard PaymentProcessor paymentProcessor
注意:
若一個bean或是一個注入點沒有被一個qualifier修飾,它會有一個預設修飾符@Default。
這還沒結束,CDI還定義了一個簡單的解決規則用來幫助容器該接下來怎麼做,當多個bean同時滿足“合同”的時候。我們會在Chapter 4,依賴注入和程式化查找章節讨論細節。
請尊重成果,如需轉載請注明來源http://equalxx.iteye.com/