當前位置:才華齋>IT認證>J2EE>

Java EE CDI方式的依賴注入方法

J2EE 閱讀(8.86K)

Java EE CDI 主要使用@Inject註解來實現依賴注入,把受管理的bean注入到由容器管理的其它資源中去。在本教程中,我們將會介紹在CDI環境下幾種不同的可選策略來實現依賴注入。

Java EE CDI方式的依賴注入方法

  本教程基於如下環境:

JDK

Weld 1.1.10

Weld 是CDI 的參考實現。

  2. 構造器依賴注入

public class SomeBean {

private final Service service;

@Inject

public SomeBean(Service service){

ice = service;

}

}

當CDI容器在初始化一個SomeBean型別的bean例項時,它將會查詢該類的預設構造器(無參構造器)並用它來建立bean例項。但是有一個例外情況,就是當我們還有一個使用@Inject 進行了註解的構造器時,這種情況下,容器會改用有註解的構造器而不是無參構造器,並且把通過構造器引數傳入的依賴資源注入到bean例項中來。

注意: 記住一個類只允許有 一個@Inject註解的構造器。

在上面的例子中,容器將會獲取到一個Service 的例項並把它注入到SomeBean 的註解構造器中。

  3. 欄位依賴注入

public class SomeBean {

@Inject

private Service service;

}

這種情況下,當容器初始化一個 SomeBean型別的bean時,它會把一個正確的Service例項注入給該欄位,即使該欄位是一個私有欄位,並且不需要有任何setter方法。

  4. 初始化方法依賴注入

public class SomeBean {

private Service service;

@Inject

public void setService(Service service) {

ice = service;

}

}

這種情況下,當容器初始化一個 SomeBean型別的bean時,它會呼叫所有由@Inject註解了的方法,並且通過方法引數的方式把依賴注入進來。

@Any 修飾符

為了提供完全鬆耦合的應用,我們通常把介面注入到受管理的資源中。當我們有多個實現了給定介面的bean時該怎麼辦呢?我們可以同時使用@Any修飾符和CDI的Instance介面,來把所有該介面的實現bean都注入進一個受管理的bean中:

The @Any qualifier

public class SomeBean {

@Inject

public void listServiceImplementations(

@Any Instance serviceList) {

for(Service service : serviceList){

tln(lass()anonicalName());

}

}

}

@Any 修飾符告訴容器,任何可供使用的依賴都適用於該注入點,所以容器會把他們都注入進來。 如果我們有介面的多個實現而我們只注入其中的一個 - 並且沒有做任何排除工作 - 那麼容器將會抱怨並且無法成功的初始化元件。我們將會在其他教程中介紹依賴排除問題。

  6.注入到生產者方法中

生產者方法的引數也可以經由CDI容器進行注入。請檢視Java EE CDI Producer methods tutorial.

  7. CDI 代理

如果我們不涉及CDI代理機制,那麼本教程將是不完整的。當我們把一個在不同於@Dependent範圍下創建出來的bean注入到另外一個託管資源時,CDI容器不會注入一個被注入bean的直接引用。

CDI 中bean 的範圍請看 Java EE CDI bean scopes

為什麼CDI使用代理? 因為如果bean的直接引用被注入,將會給被管理的bean造成諸如執行緒安全或併發訪問的問題。

設想一下一個Session 範圍的 bean被注入到一個Application範圍的bean中去的情形。由於application 範圍的bean在所有客戶端間共享,如果多個客戶端同時訪問一個application 範圍的`bean,那麼將會存在很高的風險出現這種情況:一個客戶端訪問了其他客戶端正在訪問的session範圍的bean。

為了處理這種問題,CDI創造了代理並把代理注入進注入點。由代理負責處理對被注入bean的呼叫,並實際去呼叫正確的bean例項。

CDI建立的代理繼承自被注入bean的型別。設想一下下面的情形:

Application 和 Session 範圍的 bean

@SessionScoped

public class Service {

public void doWork() {

tln("Working...");

}

}

@ApplicationScoped

public class SomeBean {

@Inject

private Service service;

public void test(){

rk();

}

}

CDI將把一個session範圍的bean的代理注入進一個application範圍的bean中去。每一次對session範圍bean的呼叫,都 將通過代理進行,代理會把呼叫重定向到正確的session範圍bean的例項,那個從屬於正確的HTTP request session的bean。

CDI建立代理是通過繼承原來bean的類,並重寫所有非私有方法。一個簡單的典型的代理的例子可以像下面這樣:

CDI 代理 示例

ublic class Service$Proxy$_$$_WeldClientProxy

extends Service {

@Override

public void doWork() {

Service instance = // ... resolve bean instance

rk();

}

}

由於CDI代理通過繼承bean的類來建立,所以當我們討論非依賴性bean範圍的時候,你應當明白CDI有如下一些限制:

CDI 不能注入原始型別

bean的類必須有一個非私有的預設構造器

bean的類不能是final型別的並且不能有任何final方法