1. 程式人生 > >spring Ioc 容器深入理解

spring Ioc 容器深入理解



IoC 概述     IOC是spring的核心,Aop、宣告式事務都能功能都依賴於此功能,它涉及程式碼解耦,設計模式,程式碼優化的問題的考量。 ioc的初步理解
    ioc的概念重要但比較晦澀難懂,如下通過一個小例子來說明這個概念:     示例場景:電影: 無間道-》角色:劉建明-》演員:劉德華
    劉德華飾演的劉建明和梁朝偉飾演的劉建明來到了天台之上,劉德華對梁朝偉說了一句經典臺詞:“我想做個好人”,我想用一個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 建立了依賴關係。