天天看點

spring Ioc 容器深入了解<一>

IoC 概述

    IOC是spring的核心,Aop、聲明式事務都能功能都依賴于此功能,它涉及代碼解耦,設計模式,代碼優化的問題的考量。

ioc的初步了解

    ioc的概念重要但比較晦澀難懂,如下通過一個小例子來說明這個概念:     示例場景:電影: 無間道-》角色:劉建明-》演員:劉德華

spring Ioc 容器深入了解<一>

    劉德華飾演的劉建明和梁朝偉飾演的劉建明來到了天台之上,劉德華對梁朝偉說了一句經典台詞:“我想做個好人”,我想用一個java類來為這天台對白的場景,進行編劇,并借此來了解ioc的概念

ioc的注入類型

    在傳統的程式設計模式中,是劇本和演員來直接耦合的,我們會發現以上劇本,是以具體角色飾演的劉德華直接侵入到劇本當中,使劇本和演員直接耦合到了一起,那麼一個明智的編劇,在劇情創作時,應該圍繞故事的角色來進行,而不應該考慮角色的具體的飾演者,這樣才能在劇本拍攝時,自由的選擇演員,而并非綁定在劉德華一個人身上,那麼通過以上的分析,我們知道需要為劇本主人公劉建明來定義一個接口。

spring Ioc 容器深入了解<一>

    如圖,就是引入角色接口的示意圖,那麼我們引入了劇本角色劉建明,而劇本的情節通過 角色來展開,在拍攝時,角色由演員來飾演,就像這幅圖一樣,其中無間道,劉建明,和劉德華三者之間的關系圖。

spring 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 建立了依賴關系。