spring迴圈依賴解決過程&Bean的生命週期
目前兩個Bean,一個TesA,一個testB,
TestA中有屬性testB,TestB中有屬性testA,並且相互注入,相互依賴。
spring能幫助我們解決屬性上的相互依賴,而不能解決構造器的依賴。
三級快取,都是map:
第一級快取, singletonObjects
第二級快取,earlySingletonObjects
第三級快取,singletonFactories (存放的是ObjectFactory<T>)
為了測試方便,我們將使用原生的xml配置檔案,使用ClassPathXmlApplicationContext測試迴圈依賴的過程。
首先
getBean(testA)
-> doGetBean(testA)
->首先來到 getSingleton(testA) -> 首先從一級快取中singletonObjects查詢,顯然剛開始沒有這個bean ,並且這個bean也沒有在建立當中,首先第一次進入這個方法,返回null。
->然後來到 getSingleton(beanName,singletonFactory)->首先從一級快取中找,顯然沒有。-> 呼叫了beforeSingletonCreation(beanName),目的是在建立這個bean之前,
先把這個beanName放到singletonsCurrentlyInCreation中,告訴容器,這個bean正在被建立。->singletonFactory.getObject();呼叫傳過來的singtonFactory的getObject方法,
注意這裡的singtonFactory是doGetBean方法的匿名內部類物件,並且裡面原本就持有了beanName,mbd,和對所在類的createBean方法的引用,相當於具備了產生bean的原材料。
->所以開始走createBean的邏輯,
首先:
先經過InstantiationAwareBeanPostProcessor後置處理器的postProcessBeforeInstantiation方法,
如果上面這個方法有返回值,那麼就繼續呼叫所有普通後置處理器的applyBeanPostProcessorsAfterInitialization方法,然後這個bean就已經被建立好了。
如果上面這個方法沒有返回值,那麼來到doCreateBean,來開始建立bean了。
->doCreateBean,呼叫createBeanInstance建立出instanceWrapper,一個包裝了bean的物件。這個時候bean已經被建立出來了,但還未設定屬性,即未初始化。好,這個時候又經過
了MergedBeanDefinitionPostProcessor後置處理器的postProcessMergedBeanDefinition方法, -> 判斷是否允許迴圈依賴,當前要建立的beanName是不是在
singletonsCurrentlyInCreation,很顯然是,因為剛剛在建立前就加入進去的嘛,
-> 上一級的條件滿足了,所以到了addSingletonFactory(beanName,singletonFactory) )方法,
注意這裡的singletonFactory是doCreateBean方法的匿名內部類物件,並且它裡面持有了beanName,mbd,和"bean",和對所在類的getEarlyBeanReference的方法的引用。
在addSingletonFactory方法中,判斷如果當前一級快取中如果沒有這個beanName的話,顯然沒有,那就把beanName和這個singletonFactory放到singletonFactories三級快取中,
注意這個singletonFactory前面說過了它是個匿名內部類物件哦。然後從二級快取中移除,這裡移除可有可無,因為這個時候二級快取裡面根本就沒有東西。
【這個時候的狀態是: 剛剛例項化了testA,然後把包含testA的一個匿名內部類物件放到了三級快取裡面,這個匿名內部類物件還持有對所在類的getEealyReference方法的引用】
->現在才開始準備給剛剛例項化的testA初始化,首先經過InstantiationAwareBeanPostProcessor後置處理器的postProcessAfterInstantiation方法,判斷是否要對當前bean進行
屬性設定,如果返回false,就不會給當前bean進行一個屬性賦值了,這個populate方法到這裡就結束了。繼續往下,判斷是否有InstantiationAwareBeanPostProcessor後置處理器
,回撥這個後置處理器的postProcessPropertyValues方法,這個方法把pvs, filteredPds, bw.getWrappedInstance(), beanName都傳進去了。然後呼叫applyPropertyValues將這些
pvs應用到bean。
->applyPropertyValues,首先new一個BeanDefinitionValueResolver,傳入了當前beanFactory等。逐個解析pvs,最終還是回到了呼叫beanFactory的getBean方法,只不過這個時候,
開始要獲取testB了
->getBean(testB)
->doGetBean(testB)
->getSingleton(beanName),先從一級快取中去拿,很顯然沒有,並且這個Bean也沒有在建立中,現在是第二次進入這個方法了哦,還是返回null,這個時候應當注意testA正在
處於建立當中,而testB沒有處在建立當中,
->然後來到 getSingleton(beanName,singletonFactory)->首先從一級快取中找,顯然沒有。-> 呼叫了beforeSingletonCreation(beanName),目的是在建立這個bean之前
先把這個beanName放到singletonsCurrentlyInCreation中,告訴容器,這個bean也正在被建立。->singletonFactory.getObject();呼叫傳過來的singtonFactory的
getObject方法,注意這裡的singtonFactory也是doGetBean方法的匿名內部類物件,並且裡面原本就持有了beanName,mbd,和對所在類的createBean方法的引用,
相當於具備了產生bean的原材料。
->createBean,同樣的繼續走testB的createBean的流程,同樣先經過InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法,如果有返回,就走所有普通
後置處理器的postProcessAfterInitialization方法。沒有返回的話走doCreateBean
->doCreateBean,繼續createBeanInstance建立出testB這個例項,但未初始化。應用MergedBeanDefinitionPostProcessor後置處理器的postProcessMergedBeanDefinition方法,
這裡判斷是否允許迴圈應用並且當前的beanName是否正在被建立,顯然之前吧testB新增進去了。
->所以就走addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))這個方法,在這個方法裡面從一級快取裡面判斷是否存在當前的beanName,顯然
不存在,就把當前的beanName和singletonFactory放到了singletonFactories三級快取中,並且從二級快取中把當前beanName移除掉,可現在二級快取根本就沒東西,無所謂。
【這個時候的狀態是: 把包含testA和testB的匿名內部類物件都分別放到了三級快取裡面,這兩個匿名內部類物件還持有對所在類的getEealyReference方法的引用,並且還持有原
beanName、mbd、bean】
->現在開始給testB進行一個初始化,跟前面testA的初始化一樣,在testB裡面找到了testA的屬性,然後去getBean(testA),然後doGetBean(testA),
好,又來到了getSingleton(beanName)這裡,
->getSingleton,先從一級快取中找,顯然沒有。接著判斷testA是否正在建立當中,很顯然是!(相當於在這裡終於檢測出來了迴圈依賴:想要獲取的bean還在當中),又先從二級緩
存中拿,二級快取這個時候是空的,拿不到。現在從三級快取中拿testA,顯然能夠拿到,之前放進去過。拿到的是ObjectFactory型別的那個匿名物件singletonFactory。接著
呼叫這個匿名物件的getObject方法,這就有意思了,原來存的() -> getEarlyBeanReference(beanName, mbd, bean)裡的這個getEarlyBeanReference方法被呼叫,方法是在
AbstractAutowireCapableBeanFactory中,在這個類的這個方法中,原先的beanName、mbd、bean都還在作為方法的引數,在這個方法裡面,
回撥SmartInstantiationAwareBeanPostProcessor後置處理器的getEarlyBeanReference方法,如果這個方法有返回值的話,那麼將替換掉bean作為exposedObject返回,這個方法
通常被用作做代理的實現。因為現在還沒有這樣的後置處理器,所以直接就返回了之前例項化的testA,注意這裡的testA是直接線從三級快取中的通過代理處理過返回的。再把
beanName和testA放到earlySingletonObjects二級快取裡面去,並且從三級快取中移除掉testA。所以這裡就相當於把三級快取中的物件經過一個代理處理後,放入二級快取,至於
代理與否,要看具體情況了。
【這個時候的狀態: 三級快取中只有一個testB相關的一個ObjectFactory物件,二級快取中有一個經過代理處理過的testA物件】
-> 獲取到物件之後,經過getObjectForBeanInstance方法,即FactoryBean的那一套拿bean的方法,獲取到bean,也就是testA嘛。
-> 然後回到testB裡面的初始化方法,拿到了testA,將testA設定給了testB。好到這裡testB的populate方法就執行完了,然後執行initializingBean。
-> initializingBean,順便也說一下這個吧
先回撥內建的Aware介面,順序依次是BeanNameAware,BeanClassLoaderAware,BeanFactoryAware。第三個介面用的比較多哦
回撥所有普通BeanPostProcessor後置處理器的postProcessBeforeInitialization方法,
回撥afterPropertiesSet方法,如果bean實現了InitializingBean介面的話。
回撥自定義的初始化方法。
回撥所有普通後置處理器的postProcessAfterInitialization方法。
這樣testB其實就已經例項化,初始化,呼叫初始化方法了。
現在流程還在testB的doCreateBean方法裡面,繼續走邏輯,
-> 判斷是否允許迴圈依賴,並且正在建立當中。如果是的話,顯然是,就走getSingleton(beanName,false),[第二個引數控制是否開啟那個代理處理過程]先從一級快取中獲取,顯然
獲取不到並且在建立當中,繼續到二級快取中去,又獲取不到,並且第二個引數限制了不從三級快取中查詢。
然後由經過了查詢beanFactory中是否配置了DestructionAwareBeanPostProcessor後置處理器,判斷當前bean是否需要銷燬,將單例bean放到beanFactory中的disposableBeans變
量中,待容器關閉後銷燬。
->這個時候testB中終於設定了testA,並且已經完成了bean的生命週期,這個時候還在getSingleton(beanName,singletonObject)方法中,
在singletonObject = singletonFactory.getObject();這個步驟成功返回了testB。
接著執行afterSingletonCreation(beanName),這是在bean成功返回之後執行的方法,把testB從singletonsCurrentlyInCreation移除掉。
【這個時候的狀態: 三級快取中只有一個testB相關的一個ObjectFactory物件,二級快取中有一個經過代理處理過的testA物件,一級快取中還沒有testA,testB。但是testB目前來
看是已經建立好了的。】
接著執行addSingleton(beanName, singletonObject);把testB放到一級快取裡面(因為testB已經完整了),把testB從三級快取中移除掉(三級快取的作用就是進行一個代理處理,
testB已經經過了這個過程了,所以不需要第二次再經過了,況且本來就先查的一級快取,所以空出空間來)
【這個時候的狀態: 三級快取中沒有,二級快取中有一個經過代理處理過的testA物件,一級快取中有testB。】
->現在testB的getSingleton(String beanName, ObjectFactory<?> singletonFactory)這個方法已經結束了,然後開始走FactoryBean取bean的那一套邏輯。
此時觀察AbstractBeanFactory中的doGetBean方法的每個情況下面都有一個bean = getObjectForBeanInstance(..)這樣的步驟在後面
->好的,現在到了testA的設定屬性的地方,這個時候是已經拿到了testB的,這個時候testA中就設定了testB的屬性。
->然後同樣是testA的initializing呼叫。
->繼然後是允許迴圈依賴,並且處於建立當中,續呼叫getSingleton(testA,false),先從一級快取中找,沒有並且正在建立當中,再從二級快取中找,這個時候是有testA的,返回它
->afterSingletonCreation把testA從singletonsCurrentlyInCreation中移除掉,
->addSingleton(beanName, singletonObject);把testA放入一級快取(因為此時A已經完整了),從三級快取中移除(此時三級快取是空的),二級快取移除掉testA(testA此時從二級緩
存中移除掉)。
->呼叫getObjectForBeanInstance按照FactoryBean的規則拿bean
到目前為止,testA和testB都已經到了一級快取裡面。
相關文章
- Spring 中 bean 的迴圈依賴SpringBean
- 24--Spring解決bean之間的迴圈依賴SpringBean
- spring解決迴圈依賴Spring
- Spring框架系列(8) - Spring IOC實現原理詳解之Bean例項化(生命週期,迴圈依賴等)Spring框架Bean
- 深談Spring如何解決Bean的迴圈依賴SpringBean
- 【spring原始碼系列】之【Bean的迴圈依賴】Spring原始碼Bean
- Spring框架是怎麼解決Bean之間的迴圈依賴的 (轉)Spring框架Bean
- 【Spring】Spring中的迴圈依賴及解決Spring
- 3.3 Spring5原始碼---迴圈依賴過程中spring讀取不完整bean的最終解決方案Spring原始碼Bean
- Spring Bean的生命週期SpringBean
- Spring Bean 的生命週期SpringBean
- Spring Bean的生命週期SpringBean
- Spring Bean生命週期SpringBean
- Spring Bean 生命週期SpringBean
- Spring如何解決迴圈依賴?Spring
- Spring迴圈依賴Spring
- Spring 迴圈依賴的三種方式(三級快取解決Set迴圈依賴問題)Spring快取
- Spring短生命週期bean注入長生命週期bean問題SpringBean
- 淺嘗Spring註解開發_Bean生命週期及執行過程SpringBean
- spring是如何解決迴圈依賴的?Spring
- Spring是如何解決迴圈依賴的Spring
- Spring中bean的生命週期SpringBean
- Spring之Bean的生命週期SpringBean
- Spring中如何解決迴圈依賴Spring
- spring通過註解註冊bean的方式+spring生命週期SpringBean
- Spring中的迴圈依賴Spring
- Spring IoC - 迴圈依賴Spring
- 再探迴圈依賴 → Spring 是如何判定原型迴圈依賴和構造方法迴圈依賴的?Spring原型構造方法
- 解決rpm包迴圈依賴
- Spring教程-Spring Bean的生命週期SpringBean
- spring: 我是如何解決迴圈依賴的?Spring
- 【Spring系列】- Spring迴圈依賴Spring
- 【Spring】Bean的LifeCycle(生命週期)SpringBean
- 面試Spring之bean的生命週期面試SpringBean
- Spring如何使用三級快取解決迴圈依賴Spring快取
- Spring原始碼分析之迴圈依賴及解決方案Spring原始碼
- 【Spring】快速理解迴圈依賴Spring
- Spring迴圈依賴+案例解析Spring