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

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

IOC 理論

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

如何理解「控制反轉」好呢?理解好它的關鍵在於咱們須要回答以下四個問題:spring

  1. 誰控制誰
  2. 控制什麼
  3. 爲什麼是反轉
  4. 哪些方面反轉了

在回答這四個問題以前,咱們先看 IOC 的定義:微信

所謂 IOC ,就是由 Spring IOC 容器來負責對象的生命週期和對象之間的關係數據結構

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

已找女友爲例(對於程序猿來講這個值得探究的問題)。通常狀況下咱們是如何來找女友的呢?首先咱們須要根據本身的需求(漂亮、身材好、性格好)找一個妹子,而後處處打聽她的興趣愛好、微信、電話號碼,而後各類投其所好送其所要,最後追到手。以下:源碼分析

/**
 * 年輕小夥子
 */
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()),這個過程複雜而又繁瑣,並且咱們必需要面對每一個環節,同時使用完成以後咱們還要負責銷燬它,在這種狀況下咱們的對象與它所依賴的對象耦合在一塊兒。學習

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

這個給咱們送東西的「人」 就是 IoC,在上面的例子中,它就至關於一個婚介公司,做爲一個婚介公司它管理着不少男男女女的資料,當咱們須要一個女友的時候,直接跟婚介公司提出咱們的需求,婚介公司則會根據咱們的需求提供一個妹子給咱們,咱們只須要負責談戀愛,生猴子就好了。你看,這樣是否是很簡單明瞭。spa

誠然,做爲婚介公司的 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

相關文章
相關標籤/搜索