【死磕 Spring】----- IOC 之深入理解 Spring IoC


在一開始學習 Spring 的時候,我們就接觸 IoC 了,作為 Spring 第一個最核心的概念,我們在解讀它源碼之前一定需要對其有深入的認識,本篇為【死磕 Spring】系列博客的第一篇博文,主要介紹 IoC 基本概念和各個組件。

IOC 理論

IoC 全稱為 Inversion of Control,翻譯為 “控制反轉”,它還有一個別名為 DI(Dependency Injection),即依賴注入。

如何理解“控制反轉”好呢?理解好它的關鍵在於我們需要回答如下四個問題:

  1. 誰控制誰
  2. 控制什么
  3. 為何是反轉
  4. 哪些方面反轉了

在回答這四個問題之前,我們先看 IOC 的定義:

所謂 IOC ,就是由 Spring IOC 容器來負責對象的生命周期和對象之間的關系

上面這句話是整個 IoC 理論的核心。如何來理解這句話?我們引用一個例子來走闡述(看完該例子上面四個問題也就不是問題了)。

已找女朋友為例(對於程序猿來說這個值得探究的問題)。一般情況下我們是如何來找女朋友的呢?首先我們需要根據自己的需求(漂亮、身材好、性格好)找一個妹子,然后到處打聽她的興趣愛好、微信、電話號碼,然后各種投其所好送其所要,最后追到手。如下:

/**
 * 年輕小伙子
 */
public class YoungMan {
    private BeautifulGirl beautifulGirl;

    YoungMan(){
        // 可能你比較牛逼,指腹為婚
        // beautifulGirl = new BeautifulGirl();
    }

    public void setBeautifulGirl(BeautifulGirl beautifulGirl) {
        this.beautifulGirl = beautifulGirl;
    }

    public static void main(String[] args){
        YoungMan you = new YoungMan();
        BeautifulGirl beautifulGirl = new BeautifulGirl("你的各種條件");
        beautifulGirl.setxxx("各種投其所好");

        // 然后你有女票了
        you.setBeautifulGirl(beautifulGirl);
    }
}

這就是我們通常做事的方式,如果我們需要某個對象,一般都是采用這種直接創建的方式(new BeautifulGirl()),這個過程復雜而又繁瑣,而且我們必須要面對每個環節,同時使用完成之后我們還要負責銷毀它,在這種情況下我們的對象與它所依賴的對象耦合在一起。

其實我們需要思考一個問題?我們每次用到自己依賴的對象真的需要自己去創建嗎?我們知道,我們依賴對象其實並不是依賴該對象本身,而是依賴它所提供的服務,只要在我們需要它的時候,它能夠及時提供服務即可,至於它是我們主動去創建的還是別人送給我們的,其實並不是那么重要。再說了,相比於自己千辛萬苦去創建它還要管理、善后而言,直接有人送過來是不是顯得更加好呢?

這個給我們送東西的“人” 就是 IoC,在上面的例子中,它就相當於一個婚介公司,作為一個婚介公司它管理着很多男男女女的資料,當我們需要一個女朋友的時候,直接跟婚介公司提出我們的需求,婚介公司則會根據我們的需求提供一個妹子給我們,我們只需要負責談戀愛,生猴子就行了。你看,這樣是不是很簡單明了。

誠然,作為婚介公司的 IoC 幫我們省略了找女朋友的繁雜過程,將原來的主動尋找變成了現在的被動接受(符合我們的要求),更加簡潔輕便。你想啊,原來你還得鞍馬前后,各種巴結,什么東西都需要自己去親力親為,現在好了,直接有人把現成的送過來,多么美妙的事情啊。所以,簡單點說,IoC 的理念就是讓別人為你服務,如下圖(摘自Spring揭秘):

201805071001

在沒有引入 IoC 的時候,被注入的對象直接依賴於被依賴的對象,有了 IoC 后,兩者及其他們的關系都是通過 Ioc Service Provider 來統一管理維護的。被注入的對象需要什么,直接跟 IoC Service Provider 打聲招呼,后者就會把相應的被依賴對象注入到被注入的對象中,從而達到 IOC Service Provider 為被注入對象服務的目的。所以 IoC 就是這么簡單!原來是需要什么東西自己去拿,現在是需要什么東西讓別人(IOC Service Provider)送過來

現在在看上面那四個問題,答案就顯得非常明顯了:

  1. 誰控制誰:在傳統的開發模式下,我們都是采用直接 new 一個對象的方式來創建對象,也就是說你依賴的對象直接由你自己控制,但是有了 IOC 容器后,則直接由 IoC 容器來控制。所以“誰控制誰”,當然是 IoC 容器控制對象。
  2. 控制什么:控制對象。
  3. 為何是反轉:沒有 IoC 的時候我們都是在自己對象中主動去創建被依賴的對象,這是正轉。但是有了 IoC 后,所依賴的對象直接由 IoC 容器創建后注入到被注入的對象中,依賴的對象由原來的主動獲取變成被動接受,所以是反轉。
  4. 哪些方面反轉了:所依賴對象的獲取被反轉了。

妹子有了,但是如何擁有妹子呢?這也是一門學問。

  1. 可能你比較牛逼,剛剛出生的時候就指腹為婚了。
  2. 大多數情況我們還是會考慮自己想要什么樣的妹子,所以還是需要向婚介公司打招呼的。
  3. 還有一種情況就是,你根本就不知道自己想要什么樣的妹子,直接跟婚介公司說,我就要一個這樣的妹子。

所以,IOC Service Provider 為被注入對象提供被依賴對象也有如下幾種方式:構造方法注入、stter方法注入、接口注入。

構造器注入

構造器注入,顧名思義就是被注入的對象通過在其構造方法中聲明依賴對象的參數列表,讓外部知道它需要哪些依賴對象。

YoungMan(BeautifulGirl beautifulGirl){
        this.beautifulGirl = beautifulGirl;
}

構造器注入方式比較直觀,對象構造完畢后就可以直接使用,這就好比你出生你家里就給你指定了你媳婦。

setter 方法注入

對於 JavaBean 對象而言,我們一般都是通過 getter 和 setter 方法來訪問和設置對象的屬性。所以,當前對象只需要為其所依賴的對象提供相對應的 setter 方法,就可以通過該方法將相應的依賴對象設置到被注入對象中。如下:

public class YoungMan {
    private BeautifulGirl beautifulGirl;

    public void setBeautifulGirl(BeautifulGirl beautifulGirl) {
        this.beautifulGirl = beautifulGirl;
    }
}

相比於構造器注入,setter 方式注入會顯得比較寬松靈活些,它可以在任何時候進行注入(當然是在使用依賴對象之前),這就好比你可以先把自己想要的妹子想好了,然后再跟婚介公司打招呼,你可以要林志玲款式的,趙麗穎款式的,甚至鳳姐哪款的,隨意性較強。

接口方式注入

接口方式注入顯得比較霸道,因為它需要被依賴的對象實現不必要的接口,帶有侵入性。一般都不推薦這種方式。


關於 IOC 理論部分,筆者不在闡述,這里推薦幾篇博客閱讀:

各個組件

先看下圖(摘自:http://singleant.iteye.com/blog/1177358)

spring-201805091002

該圖為 ClassPathXmlApplicationContext 的類繼承體系結構,雖然只有一部分,但是它基本上包含了 IOC 體系中大部分的核心類和接口。

下面我們就針對這個圖進行簡單的拆分和補充說明。

Resource體系

Resource,對資源的抽象,它的每一個實現類都代表了一種資源的訪問策略,如ClasspathResource 、 URLResource ,FileSystemResource 等。

spring-201805091003

有了資源,就應該有資源加載,Spring 利用 ResourceLoader 來進行統一資源加載,類圖如下:

spring-201805091004

BeanFactory 體系

BeanFactory 是一個非常純粹的 bean 容器,它是 IOC 必備的數據結構,其中 BeanDefinition 是她的基本結構,它內部維護着一個 BeanDefinition map ,並可根據 BeanDefinition 的描述進行 bean 的創建和管理。

spring-201805101001

BeanFacoty 有三個直接子類 ListableBeanFactoryHierarchicalBeanFactoryAutowireCapableBeanFactoryDefaultListableBeanFactory 為最終默認實現,它實現了所有接口。

Beandefinition 體系

BeanDefinition 用來描述 Spring 中的 Bean 對象。

spring-201805101002

BeandefinitionReader體系

BeanDefinitionReader 的作用是讀取 Spring 的配置文件的內容,並將其轉換成 Ioc 容器內部的數據結構:BeanDefinition。

spring-201805101003

ApplicationContext體系

這個就是大名鼎鼎的 Spring 容器,它叫做應用上下文,與我們應用息息相關,她繼承 BeanFactory,所以它是 BeanFactory 的擴展升級版,如果BeanFactory 是屌絲的話,那么 ApplicationContext 則是名副其實的高富帥。由於 ApplicationContext 的結構就決定了它與 BeanFactory 的不同,其主要區別有:

  1. 繼承 MessageSource,提供國際化的標准訪問策略。
  2. 繼承 ApplicationEventPublisher ,提供強大的事件機制。
  3. 擴展 ResourceLoader,可以用來加載多個 Resource,可以靈活訪問不同的資源。
  4. 對 Web 應用的支持。

下圖來源:https://blog.csdn.net/yujin753/article/details/47043143

spring-201805101004

上面五個體系可以說是 Spring IoC 中最核心的部分,后面博文也是針對這五個部分進行源碼分析。其實 IoC 咋一看還是挺簡單的,無非就是將配置文件(暫且認為是 xml 文件)進行解析(分析 xml 誰不會啊),然后放到一個 Map 里面就差不多了,初看有道理,其實要面臨的問題還是有很多的,下面就勞煩各位看客跟着 LZ 博客來一步一步揭開 Spring IoC 的神秘面紗。

此系列博文為 LZ 學習、研究 Spring 機制和源碼的學習筆記,會涉及參考別人的博文和書籍內容,如有雷同,純屬借鑒,當然 LZ 會標明參考來源。同時由於知識面和能力的問題,文章中難免會出現錯誤之處,如有,望各位大佬指出,不勝感激
LZ 寫此系列博客時,Spring 最新版本為 5.0.6.RELEASE ,所以此系列博客所有源碼來源均為 5.0.6.RELEASE


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM