ioc的核心是DI,目的就是提供一種更簡單的機制來設定元件依賴項,并在整個生命周期中管理這些依賴項。需要某些依賴項的元件通常被稱為依賴對象,或者在ioc的情況下被稱為目标對象。通常ioc可以分解為兩種子類型:依賴注入和依賴查找,這些子類型被進一步分解為ioc服務的具體實作。通過這個定義可以清楚的看到,當談論DI時,通常是在談論ioc,而當談論ioc時,并不總是在談論DI(依賴查找也是ioc的一種形式)。使用依賴查找時,組建必須對依賴項的引用,而使用依賴注入時,依賴項将通過ioc容器注入元件,依賴查找有兩種類型:依賴拉取,上下文依賴查找。依賴注入有兩種類型:構造函數注入和setter注入。下面一一介紹
依賴拉取
依賴拉取是最常見的ioc類型,在依賴拉取中,根據需要從系統資料庫中提取依賴項。
Spring還提供依賴拉取作為一種檢索架構所管理元件的機制:
public class DependencyPull {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring/app-context.xml");
MessageRenderer mr = applicationContext.getBean("renderer",MessageRenderer.class);
mr.render();
}
上下文依賴查找
上下文依賴朝朝在某些方面與依賴拉取類似,查找是針對管理資源的容器執行的,而不是來自某個中央系統資料庫,并且通常在某個設定點執行。
依賴查找通過元件實作以下接口來進行工作,通過實作這個接口,一個元件可以向容器發送它想要擷取依賴項的信号。
public interface ManagedComponent {
void performLookup(Container container);
public interface Container {
Object getDependency(String key);
public class ContextualizedDependencyLookup implements ManagedComponent {
private Depency depency;
public void performLookup(Container container) {
this.depency =(Depency) container.getDependency("myDependency");
當容器準備将依賴項傳遞給元件時,會依次調用每個元件的performLookup() 方法,然後元件可以使用container接口查找所需的依賴項。
構造函數注入
當在元件的構造函數中提供依賴項時,就會發生構造函數依賴注入。首先生命一個或一組構造函數,并将其依賴項作為參數,然後在元件執行個體化時由ioc容器将依賴項傳遞給元件。使用構造函數注入的一個顯而易見的結果是,如果沒有依賴項就不能建立對象,是以必須有依賴項。
public class ConstructorInjection {
private Dependency dependency;
setter注入
在setter注入中,ioc容器可以通過setter方法注入元件的依賴項。元件的setter方法公開了ioc容器可以管理的依賴項。使用setter注入的一個顯而易見的後果是,可以在沒有依賴項的情況下建立對象,然後可以通過調用setter來提供依賴項。實際上,setter注入是使用最廣泛的注入機制,也是最簡單的ioc機制之一。
public class SetterInjection {
注入與查找
現在問題來了,如果可以選擇,應該使用哪種方法,注入還是查找?答案絕對是注入。一方面,注入對元件沒有任何影響。另一方面,依賴拉取必須主動獲得對系統資料庫的引用并與其互動以擷取依賴項。
如果使用注入,則可以自由的使用與ioc容器完全分離的類,而ioc容器通過手動為他們的協作者提供依賴對象;而如果使用查找,那麼你的類總是依賴于容器定義的類和接口。查找的另一個缺點是難以獨立于容器來測試類,而使用注入則可以非常容易的測試自己的元件,因為可以通過使用适當的構造函數或setter來提供依賴項。
setter注入和構造函數注入
現在問題又來了,我們已經選擇使用注入了,但是是選擇setter注入還是構造函數注入?答案是靈活使用
當在使用元件之前必須擁有一個依賴類的執行個體時,構造函數注入就特别有用了,但如果使用構造函數注入,則可以通過一種容器無關的方式聲明對依賴項的需求,此外,構造函數注入也有助于實作不可變對象的使用。
setter注入在各種情況下都很有用。如果元件向容器公開了它的依賴項,并樂于提供自己的預設值,那麼setter注入通常是實作此目的的最佳方法。setter注入的另一個好處是,它允許在接口上聲明依賴項,盡管這種方法并沒有前面的方法有用。setter注入還允許即時交換針對不同實作的依賴項,而無須建立父元件的新執行個體。Spring的JMX支援使這項功能成為可能。也許setter注入的最大好處是,它是注入機制中侵入性最小的。
一般來說,應根據使用情況選擇注入類型。基于setter的注入允許在不建立新對象的情況下交換依賴項,并且還可以讓類選擇适當的預設值,而無須顯式注入對象。當想要確定将依賴項傳遞給元件和設計不可變對象時,構造函數注入是一個不錯的選擇。