「上一篇文章」咱們對 Spring 有了初步的認識,而 Spring 全家桶中幾乎全部組件都是依賴於 IoC 的。java
剛開始聽到 IoC,會以爲特別高大上,但其實掰開了很簡單。git
跟着個人腳步,一文帶你吃透 IoC 原理。程序員
本文主要講原理,圍繞「是何」、「爲什麼」來談,下一篇文章會講實踐部分,也就是「如何」。github
文本已收錄至個人 Github: https://github.com/xiaoqi6666/NYCSDEspring
上一篇文章有同窗問我在官網該看哪些內容,怎麼找的,那今天的截圖裏都會有連接。框架
根據上一篇文章咱們說的,Spring 全家桶中最重要的幾個項目都是基於 Spring Framework 的,因此咱們就以 Spring Framework 爲例來看文檔。ide
首先它的右側有 Github 的連接,另外點到「LEARN」這裏,就會看到各個版本的文檔。學習
那咱們點「Reference Doc」,就可以看到它的一些模塊的介紹:this
(等下... 模塊?什麼是模塊?這個問題下文回答。)spa
第一章 Overview,講述它的歷史、設計原理等等;
第二章 Core,包含了 IoC 容器,AOP 等等,那天然是講 Spring 的核心了,要點進去好好看了。
點進去以後發現了寶貴的學習資料,一切的 what, why, how 均可以在這裏找到答案。
這裏很好的解釋了大名鼎鼎的 IoC - Inversion of Control, 控制反轉。
每次讀都會有新的體會和收穫。
我粗略的總結一下:控制反轉就是把建立和管理 bean 的過程轉移給了第三方。而這個第三方,就是 Spring IoC Container,對於 IoC 來講,最重要的就是容器。
容器負責建立、配置和管理 bean,也就是它管理着 bean 的生命,控制着 bean 的依賴注入。
通俗點講,由於項目中每次建立對象是很麻煩的,因此咱們使用 Spring IoC 容器來管理這些對象,須要的時候你就直接用,不用管它是怎麼來的、何時要銷燬,只管用就行了。
舉個例子,就好像父母沒時間管孩子,就把小朋友交給託管所,就安心的去上班而不用管孩子了。
託兒所,就是第三方容器,負責管理小朋友的吃喝玩樂;
父母,至關於程序員,只管接送孩子,不用管他們吃喝。
等下,bean
又是什麼?
Bean 其實就是包裝了的 Object,不管是控制反轉仍是依賴注入,它們的主語都是 object,而 bean 就是由第三方包裝好了的 object。(想一下別人送禮物給你的時候都是要包裝一下的,本身造的就免了。
既然說容器是 IoC 最重要的部分,那麼 Spring 如何設計容器的呢?
仍是回到官網,第二段有介紹哦:
答:使用 ApplicationContext
,它是 BeanFactory
的子類,更好的補充並實現了 BeanFactory
的。
BeanFactory
簡單粗暴,能夠理解爲 HashMap:
但它通常只有 get, put 兩個功能,因此稱之爲「低級容器」。
而 ApplicationContext
多了不少功能,由於它繼承了多個接口,可稱之爲「高級容器」。在下文的搭建項目中,咱們會使用它。
ApplicationContext
的裏面有兩個具體的實現子類,用來讀取配置配件的:
ClassPathXmlApplicationContext
- 從 class path 中加載配置文件,更經常使用一些;FileSystemXmlApplicationContext
- 從本地文件中加載配置文件,不是很經常使用,若是再到 Linux 環境中,還要改路徑,不是很方便。當咱們點開 ClassPathXmlApplicationContext
時,發現它並非直接繼承 ApplicationContext
的,它有不少層的依賴關係,每層的子類都是對父類的補充實現。
而再往上找,發現最上層的 class 回到了 BeanFactory
,因此它很是重要。
要注意,Spring 中還有個 FactoryBean
,二者並無特別的關係,只是名字比較接近,因此不要弄混了順序。
爲了好理解 IoC,咱們先來回顧一下不用 IoC 時寫代碼的過程。
這裏用經典 class Rectangle
來舉例:
set()
方法和 toString()
方法注意 ⚠️:必定要生成 set()
方法,由於 Spring IoC 就是經過這個 set()
方法注入的;
toString()
方法是爲了咱們方便打印查看。
public class Rectangle { private int width; private int length; public Rectangle() { System.out.println("Hello World!"); } public void setWidth(int widTth) { this.width = widTth; } public void setLength(int length) { this.length = length; } @Override public String toString() { return "Rectangle{" + "width=" + width + ", length=" + length + '}'; } }
而後在 test
文件中手動用 set()
方法給變量賦值。
嗯,其實這個就是「解藕」的過程!
public class MyTest { @Test public void myTest() { Rectangle rect = new Rectangle(); rect.setLength(2); rect.setWidth(3); System.out.println(rect); } }
其實這就是 IoC 給屬性賦值的實現方法,咱們把「建立對象的過程」轉移給了 set()
方法,而不是靠本身去 new
,就不是本身建立的了。
這裏我所說的「本身建立」,指的是直接在對象內部來 new
,是程序主動建立對象的正向的過程;
這裏使用 set()
方法,是別人(test)給個人;
而 IoC 是用它的容器來建立、管理這些對象的,其實也是用的這個 set()
方法,不信,你把這個這個方法去掉或者改個名字試試?
何爲控制,控制的是什麼?
答:是 bean 的建立、管理的權利,控制 bean 的整個生命週期。
何爲反轉,反轉了什麼?
答:把這個權利交給了 Spring 容器,而不是本身去控制,就是反轉。
由以前的本身主動建立對象,變成如今被動接收別人給咱們的對象的過程,這就是反轉。
舉個生活中的例子,主動投資和被動投資。
本身炒股、選股票的人就是主動投資,主動權掌握在本身的手中;
而買基金的人就是被動投資,把主動權交給了基金經理,除非你把這個基金賣了,不然具體選哪些投資產品都是基金經理決定的。
回到文檔中,第二句話它說:IoC is also known as DI
.
咱們來談談 dependency injection
- 依賴注入。
何爲依賴,依賴什麼?
程序運行須要依賴外部的資源,提供程序內對象的所須要的數據、資源。
何爲注入,注入什麼?
配置文件把資源從外部注入到內部,容器加載了外部的文件、對象、數據,而後把這些資源注入給程序內的對象,維護了程序內外對象之間的依賴關係。
因此說,控制反轉是經過依賴注入實現的。
可是你品,你細品,它們是有差異的,像是「從不一樣角度描述的同一件事」
:
從而實現對象之間的解藕。
固然,IoC 也能夠經過其餘的方式來實現,而 DI 只是 Spring 的選擇。
IoC 和 DI 也並不是 Spring 框架提出來的,Spring 只是應用了這個設計思想和理念到本身的框架裏去。
那麼爲何要用 IoC 這種思想呢?換句話說,IoC 能給咱們帶來什麼好處?
答:解藕。
它把對象之間的依賴關係轉成用配置文件來管理,由 Spring IoC Container 來管理。
在項目中,底層的實現都是由不少個對象組成的,對象之間彼此合做實現項目的業務邏輯。可是,不少不少對象緊密結合在一塊兒,一旦有一方出問題了,必然會對其餘對象有所影響,因此纔有瞭解藕的這種設計思想。
如上圖所示,原本 ABCD 是互相關聯在一塊兒的,當加入第三方容器的管理以後,每一個對象都和第三方法的 IoC 容器關聯,彼此之間再也不直接聯繫在一塊兒了,沒有了耦合關係,所有對象都交由容器來控制,下降了這些對象的親密度,就叫「解藕」。
那麼咱們下一篇文章就來說一下如何搭建一個 Spring 項目。
若是你喜歡這篇文章,記得給我點贊留言哦~大家的支持和承認,就是我創做的最大動力,咱們下篇文章見!
我是小齊,紐約程序媛,終生學習者,天天晚上 9 點,雲自習室裏不見不散!
更多幹貨文章見個人 Github: https://github.com/xiaoqi6666/NYCSDE