JSR330 DI JSR 330 ,提供了一種可重用的、可維護、可測試的方式來獲取Java對象。也稱為Dependency Injection 。 DI應該都不陌生,因為它就是Spring core之一。在Spring盛行後,Google也提供了一種DI實現:Guice。因為這兩個DI容器的盛行, ...
JSR330 DI
JSR 330 ,提供了一種可重用的、可維護、可測試的方式來獲取Java對象。也稱為Dependency Injection 。
DI應該都不陌生,因為它就是Spring core之一。在Spring盛行後,Google也提供了一種DI實現:Guice。因為這兩個DI容器的盛行,JSR在2009年時誕生了。隨後Spring、Guice也相繼支持了該規範。
DI容器,也稱為Injector。可以有多種實現方式,可以基於XML、註解、DSL(Domain-specific language),甚至是Java代碼。在實現是,可以採用反射、代碼生成技術等等,均不受限制。
內容摘要:
javax.inject
下麵就說說JSR 330 規範是如何定義的:
Interface Summary |
|
Provider<T> |
Provides instances of T. |
Annotation Types Summary |
|
Inject |
Identifies injectable constructors, methods, and fields. |
Named |
String-based qualifier. |
Qualifier |
Identifies qualifier annotations. |
Scope |
Identifies scope annotations. |
Singleton |
Identifies a type that the injector only instantiates once. |
@Inject
該註解可以在constructor、field、method上使用,也可以在static 的非 final 的field、method上使用。使用該註解標註的constructor、field、method訪問修飾符不受限制,可以是private、package、protected、public中任意一種。Injector在進行註入時,要按照constructors、fiedls、methods的順序進行。
對被標註的constructor的要求:
在滿足上述說明的情況下,可以有其他的依賴作為方法的參數,別的要求倒沒有什麼。
對被標註的field的要求:
1)欄位不能是final的。
對被標註的method的要求:
1)方法不能是abstract。
2)可以有其他的依賴作為方法的參數。
如果一個@Inject 的方法A.a,被子類B重寫了方法a,但沒有指定@Inject,那麼就不會註入。
@Qualifier
它是一個元註解,用在標註一個註解的。被@Qualifier標註的註解,稱為Qualifier。用於指定採用哪個實例。
譬如說,A類有兩個子類A1,A2。B類依賴了A,那麼DI容器在為B的實例註入A依賴時到底該註入哪個實例呢?
Class B{
@Inject
A a;
}
如果使用這個註解,就可以解決該問題了:
定義來個Qualifier註解:
@Qualifier public @interface A_1 { } @Qualifier public @interface A_2 { }
然後對A1、A2兩個類分別標註,加以區分:
@A_1 public class A1{ } @A_2 public class A2{ }
如果你希望註入的是A1,那麼Class B應該這樣調整:
Class B{
@Inject
@A_1
A a;
}
在JSR 330中,也預設設計了一個基於字元串命名的Qualifier,也就是@Named。
對上述案例,可以改造如下:
@Named(“A1”) Public class A1{ } @Named(“A2”) Public class A2{ } Class B{ @Inject @Named(“A1”) A a; }
也就是說,一個Qualifier可以把一個類定義成一個依賴類(類A1,A2中的使用方式),也可以用在註入時指定註入哪個依賴類的實例(Class B中的使用方式)。
@Named
它就是上面說的,預設的Qualifier。通過上面的例子,可以將其理解為Spring中的:
@Component:用於一個類上,告訴DI容器,這個類由DI容器來創建,並可以作為依賴類去註入到其他類中。
@Qualifier:用於指定使用哪個依賴類的實例。
上述代碼在Spring中的寫法是:
@Component(“A1”)
Class A1{
}
@Component(“A2”)
Class A2{
}
Class B{
@Autowired
@Qualifier(“A1”)
A a;
}
@Scope、@Singleton
@Scope是Scope的元註解。用於聲明Scope註解。譬如@Singleton。
Scope註解,用在類上,用於告訴Injector,為該類創建多少個對象。
也預設提供了一個Scope:@Singleton,它用於告訴容器,只為該類創建一個實例。所以當一類類被標註為@Singleton時,要註意線程安全性。
如果一個@Named或者其他自定義的Qualifier標準的類,沒有被標註為@Singleton,那麼就會創建多個實例。
單實例例子:
// Spring中的寫法: @Component(“cxxx”) @Scope(“Singleton”) public class C{ } // 如果用JSR 330就可以寫為: @Named(“cxxx”) @Scope(“prototype”) public class C{ }
多實例例子:
// Spring中的寫法: @Component(“cxxx”) public class C{ } // 如果用JSR 330就可以寫為: @Named(“cxxx”) public class C{ }
Provider
一個Provider用於提供某個類的實例。它就相當於Spring中的ObjectFactory。這是一個介面,不是一個註解,所以可以像其他的類一樣使用它,它只有一個get方法。
class Car { @Inject Car(Provider<Seat> seatProvider) { Seat driver = seatProvider.get(); Seat passenger = seatProvider.get(); ... } }
我們也可以用它來解決類迴圈依賴的問題。
JSR330 vs Spring vs Guice vs HK2
功能說明 |
JSR330 |
Spring |
Guice |
HK2 |
告訴DI容器來管理一個類,並指定名稱 |
@Named | Qualifier |
@Component |
||
告訴DI容器創建幾個實例 |
@Singleton | 不寫 |
@Scope(“Singleton”) | @Scope(“prototype”) |
||
標註constructor、field、method是可住入的 |
@Inject |
@Autowired |
||
告訴DI容器註入哪個依賴 |
@Named | Qualifier |
@Qualifier |
||
自定義如何獲取對象 |
Provider |
ObjectFactory |
此外,Spring、Guice、HK2 也已經支持JSR330了,所以你可以根據功能來選擇使用JSR330的API。