IoC 概述
IOC是spring的核心,Aop、聲明式事務都能功能都依賴于此功能,它涉及代碼解耦,設計模式,代碼優化的問題的考量。
ioc的初步了解
ioc的概念重要但比較晦澀難懂,如下通過一個小例子來說明這個概念: 示例場景:電影: 無間道-》角色:劉建明-》演員:劉德華
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39TNwMTNxITMzIDOwkDM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
劉德華飾演的劉建明和梁朝偉飾演的劉建明來到了天台之上,劉德華對梁朝偉說了一句經典台詞:“我想做個好人”,我想用一個java類來為這天台對白的場景,進行編劇,并借此來了解ioc的概念
ioc的注入類型
在傳統的程式設計模式中,是劇本和演員來直接耦合的,我們會發現以上劇本,是以具體角色飾演的劉德華直接侵入到劇本當中,使劇本和演員直接耦合到了一起,那麼一個明智的編劇,在劇情創作時,應該圍繞故事的角色來進行,而不應該考慮角色的具體的飾演者,這樣才能在劇本拍攝時,自由的選擇演員,而并非綁定在劉德華一個人身上,那麼通過以上的分析,我們知道需要為劇本主人公劉建明來定義一個接口。
如圖,就是引入角色接口的示意圖,那麼我們引入了劇本角色劉建明,而劇本的情節通過 角色來展開,在拍攝時,角色由演員來飾演,就像這幅圖一樣,其中無間道,劉建明,和劉德華三者之間的關系圖。
可以在這圖當中,我們可以看到無間道同時依賴劉建明和劉德華,并沒有達到我們所期望的,劇本僅依賴與角色的目的,但是角色必須最終具體的演員來完成,那麼如果讓劉德華和劇本無關,而能完成劉建明的具體動作呢,那麼還是電影無間道這個場景,在這裡我們引入了導演,在引入導演之後,劇本和飾演者就完全解耦了。首先,我們建立了一個導演類,接下來導演要選擇一個劇本,同時,為劇本定一個角色,《劉建明》,讓劉建明這個角色插入到無間道這個劇本當中去,最後讓劉德華來飾演劉建明這個角色,你們通過引入導演之後,使劇本和具體的飾演者順利的解耦,對應到軟體當中,導演就是個裝配器,它來安排演員,來飾演具體角色。
反過來講解IOC的概念,IOC從字面上的意思,就是控制和反轉,它包含兩個内容,第一是控制,第二是反轉。它到底是什麼東西的空值并反轉呢,對應到前面 的例子。控制指的是選擇劉建明的角色扮演者的控制權,而反轉是指這種控制權,從無間道劇本中移除,轉交到導演手中,對于軟體來說,即是具一個接口的實作類的控制權,從調用類中來移除,轉接到第三方來決定,那麼IOC确實不夠開門見山,一次業界進行了廣泛的讨論,那麼最終提出了DI ,就是依賴注入,用這個概念來替代ioc,即讓調用類對一個接口實作類的依賴關系,由第三來注入,已移除調用類對于某一接口實作類的依賴,依賴注入這個詞,顯然比控制反轉直接明了,易于了解。
ioc的注入方式
從注入方法上看,主要劃為三種類型:
1、構造函數的注入 2、屬性的注入 3、接口的注入
spring構造函數注入和屬性注入。
三種注入的差別,
1、構造函數的注入,在構造函數注入當中,我們通過調用類的構造函數,來講接口實作類通過構造函數變量來注入
Public class WuJIanDao{
private LiuJianMing ljm;
// 1:注入劉建明的具體扮演者
public WuJianDao(LiuJianMing ljm){
this.ljm=ljm;
}
public void tianTai(){
ljm.declar("我想做個好人");
}
}
無間道的構造函數,不關心具體是誰來扮演劉建明這個角色,隻要代碼 1 處,去按照劇本的要求來完成相應的表演,那就可以了。那麼角色的具體的扮演者,由誰來安排呢。
Public class Director{
public void direct(){
//2.指定角色的扮演者
LiuJianMing ljm = new LiuDeHua();
//3.注入具體扮演者到劇本中
WuJianDao wjd - new WuJianDao(ljm);
wjd.tianTai();
}
}
在代碼 2 處,導演安排劉德華來飾演劉建明這個角色,并在 代碼 3 處,将劉德華注入到無間道這個劇本當中,然後開始天台對白的劇情的演出工作。那麼有時候,導演就會發現雖然劉建明是影片無間道的第一主角,但并非每個場景都需要劉建明的出現,那麼在這種情況下,通過構造函數來注入。并不是太妥當,那麼這個時候可以考慮屬性來注入。
2、屬性注入:通過Setter 方法來完成調用類所需依賴的注入,更加靈活方面和友善,
Public class WuJianDao{
private LiuJianMing ljm;
public void setLjm(LiuJianMing ljm){
this.lim=ljm
}
public void tianTai(){
ljm.cleclaer("我想做個好人");
}
}
Public class Director{
public void direct(){
//2.指定角色的扮演者
LiuJianMing ljm = new LiuDeHua();
//3.注入具體扮演者到劇本中
WuJianDao wjd - new WuJianDao(ljm);
wjd.setLjm(ljm);
wjd.tianTai();
}
}
無間道當中,通過set方法來注入劉建明角色扮演者,無間道在 1 處,為劉建明屬性提供另一個set方法,以便導演在需要使,來注入劉建明的具體扮演者,可以看代碼 2 處,這裡無間道調用屬性set方法,來講劉建明這個角色扮演者交由劉德華來進行表演。和通過構造函數注入 劉建明扮演者不同,在執行個體化無間道劇本時,并未指定任何扮演者,而在執行個體化無間道之後,在需要劉建明出場的時候,才調用set劉建明這個方法,來注入扮演者。按照類似的方式,我們還可以為劇本當中其他的角色來提供注入set 方法。這樣導演就可以根據所拍場景不通,來注入相應的角色了。
3、接口注入:将調用類所依賴注入的方法抽取到一個接口中,調用類通過實作該接口提供相應的注入方法。
我們采取接口注入的方法,首先我們要聲明一個接口,這裡我們需要聲明一個
Public interface ActorArrangable{
void injectLjm(LiuJianMing ljm );
}
Public class WuJianDao implements ActorArrangable{
private LiuJianMing ljm;
public void void injectLjm(LiuJianMing ljm ){
this.ljm=ljm;
}
public void tianTai(){
lm.clecare("我想做個好人");
}
}
Public class Director{
public void direct(){
LiuJianMing ljm = new LiuDeHua();
WuJianDao wjd = new WuJianDao(ljm);
wjd.injectLjm(ljm);
wjd.tianTai();
}
}
我們定義了一個injectLjm,在這裡我們将劉建明這個角色注入到劇本當中,然後無間道實作了該接口的具體的實作,在這個類當中,它實作了接口中的方法。通過接口方法,來注入劉建明扮演者。 接下來我們通過導演來通過ActorArrangable 的 injectLjm 方法來完成扮演者的注入工作。
那麼由于通過接口注入,需要先聲明一個接口,無疑增加了類的數量,而且效果和屬性注入并沒有本質上的卻别,是以在spring ioc 中,并不提倡采用這種方式。
雖然劇本無間道和演員劉德華實作了解耦,無間道無需關注角色實作類的執行個體化工作,但是這個工作在代碼當中,依然是存在,隻不過是轉移到了導演類中而已,那麼假設某一制片人,想改變這一局面,在選擇某一劇本之後,希望通過一個海選,或第三方中介機構來選擇導演、演員。然他們各司其職,在劇本、導演、演員都實作了解耦。那麼所謂海選和第三方結構在程式中就是第三方的容器,它幫助完成類的初始化和裝配工作。讓開發者從這些底層的類的執行個體化,依賴關系裝配中脫離出來,能夠專注業務邏輯開發的工作,這無疑是一種令人向往的事情。spring就是這麼一個容器,它通過配置檔案,或注解來描述類和類的關系,自動完成類的初始化和依賴注入的工作。
配置檔案片段 //1.實作類的執行個體化 <bean id = "ljm" class="LiuDeHua"/> // 2.通過ljm-ref 建立依賴關系 <bean id = "wjd" class="WuJianDao" p:ljm-ref="ljm"/> 在代碼 1 處,實作了類的執行個體化,在 代碼 2 處,我們通過ljm-ref 建立了依賴關系。
IoC 概述 IOC是spring的核心,Aop、聲明式事務都能功能都依賴于此功能,它涉及代碼解耦,設計模式,代碼優化的問題的考量。
ioc的初步了解
ioc的概念重要但比較晦澀難懂,如下通過一個小例子來說明這個概念: 示例場景:電影: 無間道-》角色:劉建明-》演員:劉德華
劉德華飾演的劉建明和梁朝偉飾演的劉建明來到了天台之上,劉德華對梁朝偉說了一句經典台詞:“我想做個好人”,我想用一個java類來為這天台對白的場景,進行編劇,并借此來了解ioc的概念
ioc的注入類型
在傳統的程式設計模式中,是劇本和演員來直接耦合的,我們會發現以上劇本,是以具體角色飾演的劉德華直接侵入到劇本當中,使劇本和演員直接耦合到了一起,那麼一個明智的編劇,在劇情創作時,應該圍繞故事的角色來進行,而不應該考慮角色的具體的飾演者,這樣才能在劇本拍攝時,自由的選擇演員,而并非綁定在劉德華一個人身上,那麼通過以上的分析,我們知道需要為劇本主人公劉建明來定義一個接口。
如圖,就是引入角色接口的示意圖,那麼我們引入了劇本角色劉建明,而劇本的情節通過 角色來展開,在拍攝時,角色由演員來飾演,就像這幅圖一樣,其中無間道,劉建明,和劉德華三者之間的關系圖。
可以在這圖當中,我們可以看到無間道同時依賴劉建明和劉德華,并沒有達到我們所期望的,劇本僅依賴與角色的目的,但是角色必須最終具體的演員來完成,那麼如果讓劉德華和劇本無關,而能完成劉建明的具體動作呢,那麼還是電影無間道這個場景,在這裡我們引入了導演,在引入導演之後,劇本和飾演者就完全解耦了。首先,我們建立了一個導演類,接下來導演要選擇一個劇本,同時,為劇本定一個角色,《劉建明》,讓劉建明這個角色插入到無間道這個劇本當中去,最後讓劉德華來飾演劉建明這個角色,你們通過引入導演之後,使劇本和具體的飾演者順利的解耦,對應到軟體當中,導演就是個裝配器,它來安排演員,來飾演具體角色。
反過來講解IOC的概念,IOC從字面上的意思,就是控制和反轉,它包含兩個内容,第一是控制,第二是反轉。它到底是什麼東西的空值并反轉呢,對應到前面 的例子。控制指的是選擇劉建明的角色扮演者的控制權,而反轉是指這種控制權,從無間道劇本中移除,轉交到導演手中,對于軟體來說,即是具一個接口的實作類的控制權,從調用類中來移除,轉接到第三方來決定,那麼IOC确實不夠開門見山,一次業界進行了廣泛的讨論,那麼最終提出了DI ,就是依賴注入,用這個概念來替代ioc,即讓調用類對一個接口實作類的依賴關系,由第三來注入,已移除調用類對于某一接口實作類的依賴,依賴注入這個詞,顯然比控制反轉直接明了,易于了解。
ioc的注入方式
從注入方法上看,主要劃為三種類型:
1、構造函數的注入 2、屬性的注入 3、接口的注入
spring構造函數注入和屬性注入。
三種注入的差別,
構造函數的注入,在構造函數注入當中,我們通過調用類的構造函數,來講接口實作類通過構造函數變量來注入
Public class WuJIanDao{ private LiuJianMing ljm; // 1:注入劉建明的具體扮演者 public WuJianDao(LiuJianMing ljm){ this.ljm=ljm; }
public void tianTai(){ ljm.declar("我想做個好人"); }
}
無間道的構造函數,不關心具體是誰來扮演劉建明這個角色,隻要代碼 1 處,去按照劇本的要求來完成相應的表演,那就可以了。那麼角色的具體的扮演者,由誰來安排呢。
Public class Director{ public void direct(){ //2.指定角色的扮演者 LiuJianMing ljm = new LiuDeHua(); //3.注入具體扮演者到劇本中 WuJianDao wjd - new WuJianDao(ljm); wjd.tianTai(); }
}
在代碼 2 處,導演安排劉德華來飾演劉建明這個角色,并在 代碼 3 處,将劉德華注入到無間道這個劇本當中,然後開始天台對白的劇情的演出工作。那麼有時候,導演就會發現雖然劉建明是影片無間道的第一主角,但并非每個場景都需要劉建明的出現,那麼在這種情況下,通過構造函數來注入。并不是太妥當,那麼這個時候可以考慮屬性來注入。
屬性注入:通過Setter 方法來完成調用類所需依賴的注入,更加靈活方面和友善,
Public class WuJianDao{ private LiuJianMing ljm; public void setLjm(LiuJianMing ljm){ this.lim=ljm } public void tianTai(){ ljm.cleclaer("我想做個好人"); }
}
Public class Director{ public void direct(){ //2.指定角色的扮演者 LiuJianMing ljm = new LiuDeHua(); //3.注入具體扮演者到劇本中 WuJianDao wjd - new WuJianDao(ljm); wjd.setLjm(ljm); wjd.tianTai(); }
}
無間道當中,通過set方法來注入劉建明角色扮演者,無間道在 1 處,為劉建明屬性提供另一個set方法,以便導演在需要使,來注入劉建明的具體扮演者,可以看代碼 2 處,這裡無間道調用屬性set方法,來講劉建明這個角色扮演者交由劉德華來進行表演。和通過構造函數注入 劉建明扮演者不同,在執行個體化無間道劇本時,并未指定任何扮演者,而在執行個體化無間道之後,在需要劉建明出場的時候,才調用set劉建明這個方法,來注入扮演者。按照類似的方式,我們還可以為劇本當中其他的角色來提供注入set 方法。這樣導演就可以根據所拍場景不通,來注入相應的角色了。
接口注入:将調用類所依賴注入的方法抽取到一個接口中,調用類通過實作該接口提供相應的注入方法。
我們采取接口注入的方法,首先我們要聲明一個接口,這裡我們需要聲明一個
Public interface ActorArrangable{ void injectLjm(LiuJianMing ljm ); }
Public class WuJianDao implements ActorArrangable{ private LiuJianMing ljm; public void void injectLjm(LiuJianMing ljm ){ this.ljm=ljm; } public void tianTai(){ lm.clecare("我想做個好人"); }
}
Public class Director{ public void direct(){ LiuJianMing ljm = new LiuDeHua(); WuJianDao wjd = new WuJianDao(ljm); wjd.injectLjm(ljm); wjd.tianTai(); }
}
我們定義了一個injectLjm,在這裡我們将劉建明這個角色注入到劇本當中,然後無間道實作了該接口的具體的實作,在這個類當中,它實作了接口中的方法。通過接口方法,來注入劉建明扮演者。 接下來我們通過導演來通過ActorArrangable 的 injectLjm 方法來完成扮演者的注入工作。
那麼由于通過接口注入,需要先聲明一個接口,無疑增加了類的數量,而且效果和屬性注入并沒有本質上的卻别,是以在spring ioc 中,并不提倡采用這種方式。
雖然劇本無間道和演員劉德華實作了解耦,無間道無需關注角色實作類的執行個體化工作,但是這個工作在代碼當中,依然是存在,隻不過是轉移到了導演類中而已,那麼假設某一制片人,想改變這一局面,在選擇某一劇本之後,希望通過一個海選,或第三方中介機構來選擇導演、演員。然他們各司其職,在劇本、導演、演員都實作了解耦。那麼所謂海選和第三方結構在程式中就是第三方的容器,它幫助完成類的初始化和裝配工作。讓開發者從這些底層的類的執行個體化,依賴關系裝配中脫離出來,能夠專注業務邏輯開發的工作,這無疑是一種令人向往的事情。spring就是這麼一個容器,它通過配置檔案,或注解來描述類和類的關系,自動完成類的初始化和依賴注入的工作。
配置檔案片段 //1.實作類的執行個體化 <bean id = "ljm" class="LiuDeHua"/> // 2.通過ljm-ref 建立依賴關系 <bean id = "wjd" class="WuJianDao" p:ljm-ref="ljm"/> 在代碼 1 處,實作了類的執行個體化,在 代碼 2 處,我們通過ljm-ref 建立了依賴關系。