Spring中的IOC深度解讀
spring容器
spring容器的概念,容器這個名字起的相當好,容器可以放很多東西,我們的程序啟動的時候會創(chuàng)建spring容器,會給spring容器一個清單,清單中列出了需要創(chuàng)建的對象以及對象依賴關系,spring容器會創(chuàng)建和組裝好清單中的對象,然后將這些對象存放在spring容器中,當程序中需要使用的時候,可以到容器中查找獲取,然后直接使用。
IOC:控制反轉(zhuǎn)
使用者之前使用B對象的時候都需要自己去創(chuàng)建和組裝,而現(xiàn)在這些創(chuàng)建和組裝都交給spring容器去給完成了,使用者只需要去spring容器中查找需要使用的對象就可以了;這個過程中B對象的創(chuàng)建和組裝過程被反轉(zhuǎn)了,之前是使用者自己主動去控制的,現(xiàn)在交給spring容器去創(chuàng)建和組裝了,對象的構建過程被反轉(zhuǎn)了,所以叫做控制反轉(zhuǎn);IOC是是面相對象編程中的一種設計原則,主要是為了降低系統(tǒng)代碼的耦合度,讓系統(tǒng)利于維護和擴展。
DI:依賴注入
依賴注入是spring容器中創(chuàng)建對象時給其設置依賴對象的方式,比如給spring一個清單,清單中列出了需要創(chuàng)建B對象以及其他的一些對象(可能包含了B類型中需要依賴對象),此時spring在創(chuàng)建B對象的時候,會看B對象需要依賴于哪些對象,然后去查找一下清單中有沒有包含這些被依賴的對象,如果有就去將其創(chuàng)建好,然后將其傳遞給B對象;可能B需要依賴于很多對象,B創(chuàng)建之前完全不需要知道其他對象是否存在或者其他對象在哪里以及被他們是如何創(chuàng)建,而spring容器會將B依賴對象主動創(chuàng)建好并將其注入到B中去,比如spring容器創(chuàng)建B的時候,發(fā)現(xiàn)B需要依賴于A,那么spring容器在清單中找到A的定義并將其創(chuàng)建好之后,注入到B對象中。
spring中依賴注入主要分為手動注入和自動注入:
手動注入需要由程序員自己配置、描述好依賴關系,來實現(xiàn)自動注入(但是實際開發(fā)中手動裝配的場景比較少,比如在缺少源碼的情況下可能會使用這種手動裝配情況)。
自動注入采用約定大于配置的方式來實現(xiàn)的,程序和spring容器之間約定好,遵守某一種都認同的規(guī)則,來實現(xiàn)自動注入。
DI:依賴注入的實現(xiàn)方式
分別是基于構造方法的依賴注入和基于setter(setXxxx(…))的依賴注入。
不管是手動裝配還是自動裝配都是基于這兩種方式或者變體方式來的;但是這里一定要回答到主要和變體兩個名詞,因為有的注入方式就不是這兩種,而是這兩種其中一種的變體方式;比如在一個類的屬性上面加@Autowired,這種方式注入屬性的方式就是利用了java的反射知識,field.set(value,targetObject);關于這個我在后面的文章中對spring源碼解析的時候會說明@Autowired的原理;所以@Autowired這種注入的方式是setter注入方式的一種變體
DI:依賴注入的自動裝配模型
依賴注入是一個過程,主要通過setter或構造方法以及一些變體的方式完成把對象依賴、或者填充上的這個過程叫做依賴注入,不管手動裝配還是自動裝配都有這個過程;
手動裝配通過ref標簽來指定依賴關系,而自動裝配沒有顯示的指定依賴關系,所以需要通過一些規(guī)則,來從容器中查找到符合條件的bean進行自動裝配的工作,而自動裝配模型就是完成自動裝配依賴的手段體現(xiàn)。
每一種模型都使用了不同的技術去查找和填充bean;而從spring官網(wǎng)上面可以看到spring只提出了4中自動裝配模型(嚴格意義上是三種、因為第一種是no,表示不使用自動裝配、使用),這四個模型分別用一個整形來表示,存在spring的beanDefinition當中,任何一個類默認是no這個裝配模型
我們可以在AutowireCapableBeanFactory類中看下這幾種自動裝配模型對應的整形分別是多少
public interface AutowireCapableBeanFactory extends BeanFactory { int AUTOWIRE_NO = 0; int AUTOWIRE_BY_NAME = 1; int AUTOWIRE_BY_TYPE = 2; int AUTOWIRE_CONSTRUCTOR = 3; @Deprecated int AUTOWIRE_AUTODETECT = 4; }
@Autowired就是根據(jù)byType來進行自動裝配
我們先拋出@Autowired的查找邏輯的結論:
首先spring根據(jù)類型去容器中找,找到了直接注入。如果根據(jù)類型找到了多個,那么spring不會立馬異常,而是根據(jù)名字再去找,如果根據(jù)名字找到一個合理的則注入這個合理的。
如果沒有找到,再根據(jù)名字去找,找到了則注入,沒有找到則報異常。
我們再來用代碼來驗證下
定義一個空接口I,XY類分別實現(xiàn)I接口,Z類中注入I
public interface I { }
package com.yj.service.impl; import org.springframework.stereotype.Component; import com.yj.service.I; @Component("ix") public class X implements I{ }
package com.yj.service.impl; import org.springframework.stereotype.Component; import com.yj.service.I; @Component("iy") public class Y implements I{ }
@Component public class Z { @Autowired private I ix; public I getIx() { return ix; } public void setIx(I ix) { this.ix = ix; } }
掃描配置類
package com.yj.conf; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.yj") public class AppConfig { }
MyBeanFactoryProcessor
package com.yj.conf; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.stereotype.Component; @Component public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition)beanFactory.getBeanDefinition("z"); //beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); System.out.println("beanDefinition.getAutowireMode():"+beanDefinition.getAutowireMode()); } }
首先,我們可以觀察到被@Autowired注解的z類的getAutowireMode值為0,不是2。而且我們?nèi)绻謩訉類的AutowireMode設置為ByType,只是根據(jù)類型來查找的話,會查出XY兩個bean,程序會報錯的。
但是采用@Autowired默認的注入方式,是不會報錯的,也就是說@Autowired的查找邏輯并不能簡單的認為等價于ByType,@Autowired首先根據(jù)類型然后再根據(jù)名字去查找,完成bean注入的過程。
到此這篇關于Spring中的IOC深度解讀的文章就介紹到這了,更多相關IOC深度解讀內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java創(chuàng)建線程池的7種實現(xiàn)方法
在Java中線程池是一種管理線程的機制,它可以創(chuàng)建一組線程并重復使用它們,避免了創(chuàng)建和銷毀線程的開銷,這篇文章主要給大家介紹了關于java創(chuàng)建線程池的7種實現(xiàn)方法,需要的朋友可以參考下2023-10-10對比Java中的Comparable排序接口和Comparator比較器接口
Comparable和Comparator接口都可用作普通意義上對象間的比大小,但兩個接口在實例化方面的用法不盡相同,接下來我們就來詳細對比Java中的Comparable排序接口和Comparator比較器接口2016-05-05java讀寫excel文件實現(xiàn)POI解析Excel的方法
在日常工作中,我們常常會進行Excel文件讀寫操作,這篇文章主要介紹了java讀寫excel文件實現(xiàn)POI解析Excel的方法,實例分析了java讀寫excel的技巧,非常具有實用價值,需要的朋友可以參考下2018-10-10Springboot使用redis實現(xiàn)接口Api限流的實例
本文介紹的內(nèi)容如題,就是利用redis實現(xiàn)接口的限流(某時間范圍內(nèi),最大的訪問次數(shù)),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-07-07Java httpcomponents發(fā)送get post請求代碼實例
這篇文章主要介紹了Java httpcomponents發(fā)送get post請求代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-09-09SpringBoot使用Editor.md構建Markdown富文本編輯器示例
這篇文章主要介紹了SpringBoot使用Editor.md構建Markdown富文本編輯器示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03