前言
本篇部落格會簡單介紹Spring IoC容器的知識,認識控制反轉及依賴注入。
1. IoC概述
IoC ( Inverse of Control,控制反轉 )是Spring容器的核心,AOP、宣告式實務等功能都在此基礎上開花結果,但是IoC的概念卻比較晦澀難懂,它涉及程式碼解耦、設計模式、程式碼優化等問題的考量,下面通過簡單的例子說明這個概念。
1.1 通過例項理解IoC概念
用一個簡單的劇本--《墨攻》來理解。 《墨攻》這部電影涉及三個解釋,角色墨者革離、飾演者劉德華及劇本--革離的救國行為(暫且稱為墨攻)。
public class MoAttack{
public void cityGateAsk(){
LiuDeHua ldh = new LiuDeHua;
ldh.responseAsk("我是墨者革離!");
}
}
複製程式碼
從上面劇本我們可以發現,具體飾演者劉德華直接侵入劇本,使劇本和演員直接耦合在一起。 而一部電影的編劇創作時應該圍繞故事的角色進行,而不是圍繞角色的飾演者進行。這樣在拍攝時才能保證可以自由地遴選合適的演員。 此時MoAttack同時依賴GiLi介面和LiuDeHua介面,並沒有達到我們的期望劇本僅依賴於角色。那怎麼讓LiuDeHua和劇本無關而又能完成GeLi的具體動作呢? 這就需要引入導演,導演將LiuDeHua安排在GeLi這個角色上,導負責劇本、角色、演員的協調控制。如圖所示:
通過引入導演,使劇本和演員解耦,對應軟體中,導演就像一臺裝配器,安排演員的表演的具體角色。
反過來理解IoC容器,IoC的字面意思是控制反轉,它包括兩個方面:
- 其一是控制
- 其二是反轉
對應前面例子,"控制"是指選擇GeLi角色的控制權,"反轉"是指這種控制權從劇本中移除,轉交到導演手中。對於軟體來說,即某一介面具實現類的選擇控制權從呼叫類中移除,轉交給第三方決定,即由Spring容器藉由Bean配置來控制。
因為IoC確實不夠開門見山,最終軟體界泰斗級人物Martin Fowler 提出了DI(Dependency Injection,依賴注入)的概念來代替IoC 。依賴注入顯然比控制反轉直接明瞭、易於理解。 我們來看一下這篇權威的文章:Inversion of Control Containers and the Dependency Injectionpattern
2. 控制反轉與依賴注入的關係
在一篇部落格中看到這種說法:IoC是一種思想,DI是一種設計模式,實現IoC的模式。 我個人認為IoC 不只是一種思想。更多是行為,將主控權交予第三方的行為,實現了程式的主控權的反轉。就像上面所講述的,將角色、劇本、演員的主控權交予導演(第三方)。Martin Fowler認為“控制反轉”這個概念太泛了,於是決定將這個模式叫做”依賴注入”(Dependency Injection)。
3. 依賴注入的三種方法
從注入方法上看,IoC主要可以劃分為3中種型別:建構函式注入、屬性注入和介面注入。Spring支援建構函式注入和屬性注入。
3.1 建構函式注入
在建構函式中,通過呼叫類的建構函式,將介面實現類通過構造函變數傳入。
public class MoAttack{
private GeLi geli;
//注入革離得具體飾演者
public MoAttack(GeLi geli){
this.geli = geli;
}
public void cityGateAsk(){
geli..responseAsk("墨者革離!");
}
}
複製程式碼
MoAttack 的建構函式不關心具體由誰飾演革離這個角色,只需按劇本完成相應的表演即可,角色的具體飾演者將由導演來安排。
public class Directer{
public void directer(){
//指定角色的飾演者
GeLi geli = new LiuDeHua();
//注入具體飾演者到劇本中
MoAttack moAttack = new MoAttack(geli);
moAttack.cityGateAsk();
}
}
複製程式碼
3.2 屬性注入
對於JavaBean物件來說,通常會通過setXXX()和getXXX()來訪問對應屬性。通過setter方法,可以更改相應的物件屬性。所以當前物件只要為其依賴物件所對應的屬性新增setter方法,就可以通過setter方法將相應的依賴物件設定到被注入物件中。
public class MoAttack{
private GeLi geli;
//屬性注入的方法
public MoAttack(GeLi geli){
this.geli = geli;
}
public void cityGateAsk(){
geli..responseAsk("墨者革離!");
}
}
複製程式碼
public class Directer{
public void directer(){
MoAttack moAttack = new MoAttack();
//呼叫屬性setter方法注入
GeLi geli = new LiuDeHua();
moAttack.setGeli(geli);
moAttack.cityGateAsk();
}
}
複製程式碼
3.3 介面注入
除了前面兩種注入技術,還可以在介面中定義需要注入的資訊,並通過介面完成注入。首先,我需要定義一個介面,元件的注入將通過這個介面進行。 但是從注入方式的使用來說,介面注入是現在不提倡的一種方式,基本處於”退役”狀態,因為它強制被注入物件實現不必要的介面。
4. 通過容器完成依賴關係的注入
除了上述幾種方法還有一種方法時通過容器來完成注入。這種方法因為涉及Java的反射知識和類裝載器,所以就不詳細介紹了。 簡單理解容器完成依賴注入,就是一個第三方容器來幫助類的初始化與裝配工作,讓開發者從這些底層實現類的例項化、依賴關係裝配等工作中解脫出來,專注於更有意義的業務邏輯開發工作。
5. 小結
對於初學Spring來說,IoC 是可以幫助我們解耦各業務物件間依賴關係的物件繫結方式,理解Ioc和DI能夠更好地幫助我們使用Spring框架。