IOC是「Inversion of Control」的縮寫,翻譯過來就是「控制反轉」。javascript
咱們先不深究其在Spring中的含義,先從字面上進行分析。打個比方來講:結婚前你的工資徹底由你來支配,想怎麼花就怎麼花。結婚後變了,你的錢要上交給你媳婦了,你想花的時候得申請。此時你對工資的控制轉變了,由原來的你控制,變成了你媳婦控制。這就是「控制反轉」,原本屬於你控制的事情,交由別人來控制,而你只在須要的時候進行獲取就能夠了。java
Spring全家桶地址框架
相信經過這個比喻你們對「控制反轉」的含義都已經理解了,那麼它在Spring中的體現就是:把建立對象的過程交給Spring來進行管理,從而作到將原來須要本身手動new對象,變成直接從Spring中獲取。ide
這就就比如Spring中有一個容器,咱們將Bean放到這個容器中,讓這個容器爲咱們建立實例,當須要時咱們直接從這個容器中進行獲取便可。這個容器的實現理念就是IOC。spa
使用IOC最大的好處就是減小了代碼的耦合度,下降了程序的維護成本。可能不少人都知道這個道理,就是不太明白它究竟是怎麼下降的,別慌下面讓我來給你們講解一下。翻譯
假設如今有一道菜:宮保雞丁。code
// 僞代碼 public class KungPaoChicken { public static KungPaoChicken getKungPaoChicken(各類食材) { // 加工各類食材最終獲得一份美味的宮爆雞丁。 return KungPaoChicken; } }
若是如今不使用IOC,咱們想要吃到宮保雞丁,那麼就須要以下操做。xml
// 僞代碼 public class Person() { // 採購各類食材 // 準備好各類食材經過KungPaoChicken獲取到一份宮保雞丁。 KungPaoChicken kungPaoChicken = KungPaoChicken.getKungPaoChicken(各類食材); }
代碼之間的耦合關係圖:對象
看起來也不難,也不麻煩對吧?blog
彆着急下定論,如今只是一我的想要宮保雞丁,假如如今有10我的都想要那?是否是有十份相同的代碼?這10我的都和KungPaoChicken有耦合。又好比如今須要的食材有所改變,那這樣的話是否是這10我的都須要調整代碼?這麼一來是否是發現這種實現方式一點也不友好。
使用IOC的作法如今咱們轉變一下思路,再也不本身動手作了,咱們把這道菜的作法告訴飯店,讓飯店來作。
// 僞代碼 public class Restaurant { public static KungPaoChicken getKungPaoChicken() { // 處理食材,返回宮保雞丁 retur KungPaoChicken; } }
轉變以後的耦合關係圖:
通過這樣處理,就能夠很大程度上解決上面的這些問題。
一、咱們將KungPaoChicken交給Restaurant(飯店)來進行管理,它的建立由Restaurant進行。
二、如今不管是1我的仍是10我的咱們只須要從Restaurant中進行獲取就能夠了。這樣耦合就改變了,Person只須要和Restaurant發生耦合就能夠了。
三、當KungPaoChicken有變更時,也不須要每一個人都變更,只須要Restaurant隨之改變就能夠了。
Spring的IOC容器就充當了上面案例中的Restaurant角色,咱們只須要告訴Spring哪些Bean須要Spring進行管理,而後經過指定的方式從IOC容器中獲取便可。
Spring提供的IOC容器Spring提供了一個接口BeanFactory。這個接口是Spring實現IOC容器的頂級接口,這個接口是Spring內部使用的,並非專門爲框架的使用者提供的。
咱們通常使用的是BeanFactory的子接口ApplicationContext接口,這個接口提供了更多而且更增強大的功能。
在ApplicationContext接口中有三個經常使用的實現類分別是:AnnotationConfigApplicationContext、FileSystemXmlApplicationContext、ClassPathXmlApplicationContext。
容器的建立須要讀取配置文件或配置類,經過這些配置告訴Spring哪些bean是須要Spring來進行管理的。
注意:讀取配置文件時,若是讀取絕對路徑時入參須要添加前綴「file:」,讀取相對路徑時入參須要添加「classpath:」。
做用:用於在全註解開發時,讀取配置類的相關配置信息。
注意:經過@Configuration註解標註當前類爲Spring的配置類
ApplicationContext context = new AnnotationConfigApplicationContext(自定義的配置類.class);
做用:默認加載classPath下的配置文件,也就是代碼編譯以後的classes文件夾下。
注意:使用ClassPathXmlApplicationContext讀取相對路徑時入參的「classpath:」是能夠省略的。讀取絕對路徑時,須要在入參添加前綴「file:」。
示例代碼
// 相對路徑 ApplicationContext context = new ClassPathXmlApplicationContext("classpath:配置文件名稱.xml"); ApplicationContext context = new ClassPathXmlApplicationContext("配置文件名稱.xml"); // 絕對路徑 ApplicationContext context = new ClassPathXmlApplicationContext("file:絕對路徑下的配置文件路徑");
做用:默認加載的是項目的所在路徑下的配置文件。注意:對FileSystemXmlApplicationContext來講讀取絕對路徑時的入參前綴「file:」是能夠省略的,可是讀取相對路徑的入參「classpath:」是必須的。
示例代碼
// 相對路徑 ApplicationContext context = new FileSystemXmlApplicationContext("classpath:beans.xml"); // 絕對路徑 ApplicationContext context = new FileSystemXmlApplicationContext("file:絕對路徑下的配置文件路徑"); ApplicationContext context = new FileSystemXmlApplicationContext("絕對路徑下的配置文件路徑"); // 直接從項目的路徑下 ApplicationContext context = new FileSystemXmlApplicationContext("src\main\resources\配置文件名");Spring的IOC實現原理
Spring實現IOC容器的是經過:工廠 + 反射,實現的。
經過一張圖來給你們講解SpirngIOC的實現原理(基於XML配置文件)
若是是基於全註解形式的話,只是將讀取配置文件的步驟改爲了讀取配置類,而後經過配置類獲取須要建立實現的Bean,並經過反射將其建立。其總體實現思路和使用XML配置文件是同樣的。