[Spring] 我對 Spring IOC 的理解

剛開始學習 Spring 的時候,常常會搜索一些文章去嘗試瞭解 IOC 這個概念。後來看多了,雖然大佬的博客解釋的非常精彩,栗子也舉得高高的。但是沒親自去探究,去專研,一直還是一知半解的。

 

首先,IOC 這是一種面向對象的設計原則,可以用來減低計算機代碼之間的耦合度。

IOC 的解釋爲 Inversion of Control 控制翻轉

這個名字一看是對初學者來說是有點懵逼的。但是掌握這個詞對於理解這個概念,是非常有必要的。

想想我們剛開始學 Java 的時候,我們是這樣的

 

圖 1-1
圖 1-1

 

通過 new 這個關鍵字來創建一個對象。你想想,這種創建行爲其實就是我們主動發起的,也就是說創建對象的控制權在手裏。

再回來看“控制翻轉”這個詞,換種說法來解釋控制權調換了,已經不在我們這裏了。

既然上面說控制權不在我們這裏,那去哪裏了?

主角登場了! 其實控制權交給了 Spring。交給 Spring 有啥好處?跟我們平時 new 一個對象有啥區別?

好處在於,不用我們親自去 new 了。請看下圖

 

圖 1-2

 

圖 1-2 中,代碼解釋是,通過傳入資源文件 beans.xml(資源文件是描述需要注入的 bean 信息,包括 bean 在 容器中的標識、生命週期函數等),由 ClassPathXMLApplicationContext 負責定位,讀取,加載 Bean 的信息進入 Spring 容器中。然後我們通過 Beanname 來到容器裏面獲取相應的 Bean。

說明一點是,Spring 容器是在 ApplicationContext 裏面的。關於 Spring 容器和 Context 之間的關係以後有機會再講,裏面涉及到了一些其他的設計模式。

上面已經說完了代碼的方式來實現使用 IOC。

那你可能有疑問,爲什麼這麼麻煩!還要創建 xml 還要建立工廠,太麻煩了。還不如直接 new 一個來的直接,一行代碼就可以滿足了。

上面已經說了,IOC 是一種架構設計的思路,並不僅是爲了減少代碼量而生。直接 new 對象和注入對象兩者的最終目的,都是爲了獲取自己想要的對象引用,從而執行相應的方法來完成邏輯。但問題在於,如果我們把獲取引用的機會留給一個總部(相當於一個控制檯),然後通過控制檯,去控制整個項目的代碼各個地方什麼時候能獲取到引用,什麼時候執行,什麼時候銷燬等等,這就相當於簡化、減少我們去思考一些問題,例如“什麼時候創建對象”、“什麼時候回收對象”,這就不會出現難以難以維護和調試的情況。同時,由 IoC 容器來管理對象的生命週期、依賴關係,從而是應用程序的配置和依賴規範與實際程序分開了。要是想修改啥參數,直接修改配置文件即可,代碼完全不用動。

由此可見,IOC 這種思想的最終目的,其實就是將實例化對象的控制權從我們手裏轉交給了控制檯(容器)也進行統一處理。

我們需要做的是配置資源文件 (可能在 xml 文件,也可能是以註解的方式或其他別的文件,讓容器尋找並加載)、然後我們只需要在編碼中配置好注入方式,容器會根據你所定義的信息進行資源注入。在整個項目啓動到結束,IOC 會幫你管理 bean 的整個生命週期,例如在容器中統一管理、統一對對象進行銷燬等等。

還有一個好處,在 Spring 容器中,我們擁有多種 Bean 的作用域,通過 Spring 容器我們可以隨意根據需求選擇。

 

## 關於注入的方式

讓我說的話,控制翻轉(IOC)是一種行爲的描述。所以實現的策略也是有不同的。策略一是,依賴注入(Dependency Injection)、策略二是依賴查找(Dependency Lookup)。

根據百度的查找,我貼一下這兩種策略的差別:

依賴查找:容器提供回調接口和上下文條件給組件。EJB和Apache Avalon 都使用這種方式。這樣一來,組件就必須使用容器提供的API來查找資源和協作對象,僅有的控制反轉只體現在那些回調方法上(也就是上面所說的 類型1):容器將調用這些回調方法,從而讓應用代碼獲得相關資源。

依賴注入:組件不做定位查詢,只提供普通的Java方法讓容器去決定依賴關係。容器全權負責的組件的裝配,它會把符合依賴關係的對象通過JavaBean屬性或者構造函數傳遞給需要的對象。通過JavaBean屬性注射依賴關係的做法稱爲設值方法注入(Setter Injection);將依賴關係作爲構造函數參數傳入的做法稱爲構造器注入(Constructor Injection)

一般在真實代碼中,我們不會說直接像圖 1-2 那樣編碼性從容器獲取 Bean。在 Spring 中,選擇實現的方式是依賴注入。而注入的方式有以下這幾種:

  1. 接口注入
  2. Setter 注入:當 IOC 容器檢測到需要某個屬性,就會調用 setter 方法去將對象注入
  3. 構造器注入
  4. 註解注入:@Service @Reposity @Resource

 

## IOC 的實現基礎是什麼?

其實我知道很多人都明白,IOC 能夠得到應用,很大程度上是因爲 Java 擁有反射的特性。曾經測試過,反射的性能會比直接 new 一個對象慢很多。可以說,new 一個對象是 1ms,反射估計得 100ms 以上。這點還是感覺很浪費。但是我跟你說,這個結果可是經過不斷優化後,才能達到效果。所以,使用反射的成本還不是很高的。

對於工程項目來說,反射會拖慢執行效率的時候估計是在項目啓動的時候,會電腦的花銷會很大。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章