spring迴圈依賴解決過程&Bean的生命週期

qq_16992475發表於2020-12-17

目前兩個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都已經到了一級快取裡面。

          


              


 

相關文章