Spring揭祕——什麼是IOC和DI

一、IoC的基本概念

IoC全稱Inversion of Control,即控制反轉。它的核心技術是DI (Dependency Injection),即依賴注入。
什麼是IOC?打個比方,我們要做一個系統,爲客戶提供股票新聞。通常我們需要從不同的新聞社訂閱新聞來源,然後通過批處理程序定時到指定的新聞服務器抓取最新的股票新聞,接着保存數據庫,最後在前端顯示。代碼如下:

public class FXNewsProvider
{
	private IFXNewsListener newsListener;
	private IFXNewsPersister newPersistener;
	public void getAndPersistNews()
	{
		String[] newsIds = newsListener.getAvailableNewsIds();
		if(ArrayUtils.isEmpty(newsIds))
			{
			return;
			}
				for(String newsId : newsIds)
				{
				FXNewsBean newsBean = newsListener.getNewsByPK(newsId);
				newPersistener.persistNews(newsBean);
				newsListener.postProcessIfNecessary(newsId);	
			}
	}
}

其中, FXNewsProvider 需要依賴 IFXNewsListener 來幫助抓取新聞內容,並依賴 IFXNews-
Persister 存儲抓取的新聞。
假設默認使用道瓊斯(Dow Jones)新聞社的新聞,那麼我們相應地提供了 DowJonesNewsLis-
tener 和 DowJonesNewsPersister 兩個實現。通常情況下,需要在構造函數中構造 IFXNewsProvider
依賴的這兩個類:

public FXNewsProvider() {
        this.newsListener = new DowJonesNewsListener();
        this.newPersistener = new DowJonesNewsPersister();
    }

以往,如果我們依賴於某個類或服務,最簡單而有效的方式就是直接在類的構造函數中新建相應的依賴類。我們都是自己主動地去獲取依賴的對象!
IoC則是在我們需要時將某個依賴對象送過來,它的反轉,就反轉在讓你從原來的事必躬親,轉變爲現在的享受服務。

二、依賴注入

被注入對象又是通過哪些什麼來通知IoC爲其提供適當服務的呢?其實就是依賴注入!依賴注入主要有兩種方式:1、構造方法注入;2、setter方法注入

2.1 構造方法注入

顧名思義,構造方法注入,就是被注入對象可以通過在其構造方法中聲明依賴對象的參數列表,讓IoC容器知道它需要哪些依賴對象。對於前面例子中的 FXNewsProvider 來說,只要聲明如下構造方法即可支持構造方法注入。

public FXNewsProvider(IFXNewsListener newsListner,IFXNewsPersister newsPersister)
{
	this.newsListener = newsListner;
	this.newPersistener = newsPersister;
}

IoC會檢查被注入對象的構造方法,取得它所需要的依賴對象列表,進而爲其注入相應的對象。同一個對象是不可能被構造兩次的,因此,被注入對象的構造乃至其整個生命週期,應該是由IoC來管理的。構造方法注入方式比較直觀,對象被構造完成後,即進入就緒狀態,可以馬上使用。

2.2 setter 方法注入

當前對象只要爲其依賴對象所對應的屬性添加setter方法,就可以通過setter方法將相應的依賴對象設置到被注入對象中。以 FXNewsProvider 爲例,添加setter方法後如下所示。

public class FXNewsProvider
{
	private IFXNewsListener newsListener;
	private IFXNewsPersister newPersistener;
	public IFXNewsListener getNewsListener() {
		return newsListener;
	}
	public void setNewsListener(IFXNewsListener newsListener) {
		this.newsListener = newsListener;
	}
	public IFXNewsPersister getNewPersistener() {
		return newPersistener;
	}
	public void setNewPersistener(IFXNewsPersister newPersistener) {
		this.newPersistener = newPersistener;
	}
}

這樣,外界就可以通過調用 setNewsListener 和 setNewPersistener 方法爲 FXNewsProvider 對象注入所依賴的對象了。
setter方法注入雖不像構造方法注入那樣,讓對象構造完成後即可使用,但相對來說更寬鬆一些,可以在對象構造完成後再注入。

2.3 兩種注入方式的比較

構造方法注入的優點就是,對象在構造完成之後,即已進入就緒狀態,可以馬上使用。缺點就是,當依賴對象比較多的時候,構造方法的參數列表會比較長。而通過反射構造對象的時候,對相同類型的參數的處理會比較困難,維護和使用上也比較麻煩。而且在Java中,構造方法無法被繼承,無法設置默認值。對於非必須的依賴處理,可能需要引入多個構造方法,而參數數量的變動可能造成維護上的不便。

setter方法注入因爲方法可以命名, 所以setter方法注入在描述性上要比構造方法注入好一些。
另外,setter方法可以被繼承,允許設置默認值,而且有良好的IDE支持。缺點當然就是對象無
法在構造完成後馬上進入就緒狀態。

三、IOC的優點

不使用IOC看上去照樣可以實現功能,但是如果需求發生變化了,比如需求追加了處理另一家新聞社的新聞來源時,問題就來了。因爲我們之前沒有用IoC,所以,現在的對象跟 DowJonesNewsListener 是綁定
的,我們無法重用這個類了。
而使用IoC後,我們卻完全可以不做任何改動,因爲不管是DowJones還是MarketWin24,對於我們的系統來說,處理邏輯實際上應該是一樣的。因此,我們只要根據MarketWin24的新聞服務接口,爲MarketWin24的 FXNewsProvider 提供相應的 MarketWin24NewsListener 注入就可以了,見以下代碼:

FXNewsProvider dowJonesNewsProvider =new FXNewsProvider(new DowJonesNewsListener(),new DowJonesNewsPersister());
...
FXNewsPrivider marketWin24NewsProvider =new FXNewsProvider(new MarketWin24NewsListener(),new DowJonesNewsPersister());
...

IoC是一種可以幫助我們解耦各業務對象間依賴關係的對象綁定方式!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章