CDI服務

前言

CDI(Contexts and Dependency Injection 上下文依賴注入),是JAVA官方提供的依賴注入實現,可用於Dynamic Web Module中,將依賴注入IOC/DI上升到容器級別, 它提供了Java EE平臺上服務注入的組件管理核心,簡化是CDI的目標,讓一切均可以被註解被注入。CDI是爲解耦而生.如Spring主要用途是AOP.IOC(DI),而CDI除了DI外,AOP功能也是有的.從實際使用上來看,CDI比Spring功能更豐富,更靈活,其代價也是有的,學習成本相對spring較高. java

1.CDI致力於鬆耦合,強類型.

實現鬆散耦合的三種方式: 
spring

  1. 部署時候的多態選擇,@alternatives 
  2. producer methods在運行時的多態.
  3. 上下文相關的生命週期管理與bean生命週期解耦。

這些技術使客戶端和服務器的鬆散耦合服務。客戶端再也不是緊密地綁定到一個接口的一個實現,也不須要管理生命週期實現。這種方法容許有狀態的對象看成服務交互。鬆散耦合使系統更具活力。在之前,框架老是犧牲了類型安全(尤爲是經過使用XML描述符,Spring2.5)。 

CDI提供了三個額外的重要措施,進一步鬆耦合: 
安全

  1. 在業務邏輯層用攔截器技術解耦.
  2. 修飾符(註解)能夠用來分離一些業務問題
  3. 用CDI EVENT技術進行解耦事件生產者與消費者.

第二個CDI是強類型的.不管是依賴關係的信息,攔截器,修飾符的Bean,以及CDI event的生產者,消費者等的信息所有都是類型安全的.由編譯器進行驗證. 
CDI是確確實實沒String標識符,如xml配置什麼的.好比Spring2.5用XML配置,其實都是字符串,以及"約定大於配置"的概念.在CDI裏是沒有的.CDI框架不是隱藏,而是沒有. 
這種方法的最明顯好處就是任何IDE均可以提供自動完成,驗證以及最重要的重構!(瞭解JPA的,能夠對比安全類型的查詢和JPQL.若是重構代碼JPQL是很是麻煩的). 
還有個好處就是你在識別不一樣的對象,事件,攔截器能夠經過註解而不是字符串名字,這樣你能夠提高代碼質量. 

CDI鼓勵開發使用註解.如 
  @Asynchronous,   
  @Secure, 
  @Updated, 
而不是使用複合名稱, 
  asyncPaymentProcessor, 
  SecurityInterceptor 
  DocumentUpdatedEvent. 
這也符合代碼大全裏的一些概念.只不過不用費盡心思考慮命名了,這樣更簡潔高效. 
註釋是可重用的。他們幫助描述系統的不一樣部分的共同特質。他們幫助咱們分類和理解代碼。他們幫助咱們應對常見問題的經常使用方法。他們使咱們的代碼更簡潔高效. 
服務器

2.高級功能Producer methods

先貼一段代碼,下面都用到框架

 1 import javax.enterprise.inject.Produces;
 2 
 3 @SessionScoped
 4 public class Preferences implements Serializable {
 5 
 6    private PaymentStrategyType paymentStrategy;
 7 
 8    ...
 9 
10    @Produces @Preferred 
11    public PaymentStrategy getPaymentStrategy() {
12        switch (paymentStrategy) {
13            case CREDIT_CARD: return new CreditCardPaymentStrategy();
14            case CHECK: return new CheckPaymentStrategy();
15            case PAYPAL: return new PayPalPaymentStrategy();
16            default: return null;
17        } 
18    }
19 }
20 //注入一個Producer methods
21 @Inject @Preferred PaymentStrategy paymentStrategy;

A:Producer methods的Scope

Producer methods的默認範圍是@Dependent. 
從上面代碼咱們能夠思考一種場景,那就是一個用戶會話中有多個PaymentStrategy對象的實例.若是想改變,咱們能夠在Producer方法上添加一個@SessionSciped註解. 
如今,若是一個用戶調用了這個Producer methods,那麼返回的這個PaymentStrategy對象的實例將綁定到會話的上下文.Producer methods不會再實例化另外一個出來. 
async

 

1 @Produces @Preferred @SessionScoped
2 public PaymentStrategy getPaymentStrategy() {
3    ...
4 }

 

注意:Producer methods不繼承聲明此Producer methods的Bean的Scope. 
其實這裏有2個不一樣的Bean:Producer methods(至關於一個Bean)以及聲明這個生產方法的Bean.
ide

B: Injection into producer methods

在Producer methods一開始的實例有一個潛在的問題
CreditCardPaymentStrategy 的實現使用 Java new 運算符來實例化。學習

private PaymentStrategyType paymentStrategy;

而producer methods應該理解爲一個獨立的Bean,而paymentStrategy是從Preferences 中用new實例化的.因此咱們應該使用下面這種方式來使用producer methods方法.spa

 1 @Produces @Preferred @SessionScoped
 2 public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps,
 3                                           CheckPaymentStrategy cps,
 4                                           PayPalPaymentStrategy ppps) {
 5 
 6    switch (paymentStrategy) {
 7       case CREDIT_CARD: return ccps;
 8       case CHEQUE: return cps;
 9       case PAYPAL: return ppps;
10       default: return null;
11    } 
12 }

這裏會有問題,若是CreditCardPaymentStrategy 是一個@RequestScope,那這裏必然是要發生錯誤的.由於注入的CreditCardPaymentStrategy Bean實例是request,在@SessionScoped使用前容器就會進行銷燬.那麼就出錯了..net

這是個問題,因此咱們有3種處理方案.

  1.  producer method to @Dependent or @RequestScoped.<最好的方式>
  2. CreditCardPaymentStrategy 更改Scope,但這可能會影響其餘的地方,不是很好.
  3. 使用@New限定符,但在CDI 1.1 @New限定符被棄用。CDI鼓勵應用程序注入@Dependent範圍bean。

C:Use of @New with producer methods<不推薦>

Consider the following producer method:

 

 1 @Produces @Preferred @SessionScoped
 2 public PaymentStrategy getPaymentStrategy(@New CreditCardPaymentStrategy ccps,
 3                                           @New CheckPaymentStrategy cps,
 4                                           @New PayPalPaymentStrategy ppps) {
 5    switch (paymentStrategy) {
 6       case CREDIT_CARD: return ccps;
 7       case CHEQUE: return cps;
 8       case PAYPAL: return ppps;
 9       default: return null;
10    } 
11 }

這將會建立一個新的CreditCardPaymentStrategy依賴實例,傳遞到生產方法,依賴對象不會被摧毀,直到會話結束。

在CDI 1.1 @New限定符被棄用。CDI鼓勵應用程序注入@Dependent範圍bean。

D:Disposer methods

一些Procucer methods返回的對象須要顯式的破壞。例如,有人須要關閉這個JDBC鏈接: 

 

1 @Produces @RequestScoped 
2 Connection connect(User user) {
3 
4    return createConnection(user.getId(), user.getPassword());
5 }

 

而在一個相同的類中,disposer method能夠進行匹配. 

 

1 void close(@Disposes Connection connection) {
2 
3    connection.close();
4 }

 

說明:在同一個類中,disposer method能夠進行匹配類型爲Connection 的Procucer methods,從而在 Procucer methods週期結束後進行jdbc的連接關閉. 

以下面這個:

 

 1 import javax.enterprise.context.RequestScoped;
 2 import javax.enterprise.inject.Disposes;
 3 import javax.enterprise.inject.Produces;
 4 import javax.enterprise.inject.spi.InjectionPoint;
 5 import javax.persistence.EntityManager;
 6 import javax.persistence.EntityManagerFactory;
 7 import javax.persistence.PersistenceUnit;
 8 
 9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11 
12 public class Resources {
13 
14     @PersistenceUnit
15     private EntityManagerFactory entityManagerFactory;
16 
17     @Produces
18     @RequestScoped
19     protected EntityManager createEntityManager() {
20 
21         return entityManagerFactory.createEntityManager();
22     }
23 
24     //參數必須對應上面方法的返回值
25     protected void closeEntityManager(@Disposes EntityManager entityManager) {
26 
27         if ( entityManager.isOpen() )
28         {
29             entityManager.close();
30         }
31     }
32 }

 

參考連接:https://my.oschina.net/zhaoqian/blog/263422#h1_1

相關文章
相關標籤/搜索