天天看點

spring 循環依賴_Spring 是如何解決循環依賴的?Spring 是如何解決循環依賴的?

Spring 是如何解決循環依賴的?

循環依賴:

spring 循環依賴_Spring 是如何解決循環依賴的?Spring 是如何解決循環依賴的?

Spring 循環依賴有三種情況:

  1. 構造器的循環依賴,這種依賴 Spring 無法處理,直接抛出 BeanCurrentlyInCreationException 異常
  2. 單例模式下的 setter 循環依賴,可以通過三級緩存處理
  3. 非單例循環依賴,無法處理,BeanCurrentlyInCreationException 異常

構造器循環依賴

正要建立的 bean 記錄在緩存中,Spring 容器架構一個正在建立的 bean 辨別符放在一個 “目前建立 bean 池”中國, 是以如果在建立 Bean 過程中,如果發現已經在目前建立的 Bean 池中,則抛出 BeanCurrentlyInCreationException 異常表示循環依賴,對于建立完畢的 Bean 将從“目前建立 Bean 池”中清除。 先看個例子:

xml 配置

測試代碼

報錯如下:

Setter 注入(單例)

測試代碼

運作時不會報錯的.

Setter 注入(非單例模式)

對于 prototype 作用域的 Bean ,Spring 容器無法完成依賴注入,因為 Prototype 作用域的bean ,sring 不進行緩沖,無法提提前暴露一個建立中的Bean。會抛出異常。

測試代碼

報錯

Spring  Bean 建立過程

spring 循環依賴_Spring 是如何解決循環依賴的?Spring 是如何解決循環依賴的?
  1. 執行個體化 Bean 對象,createBeanInstance 執行個體化
  2. 設定 Bean 屬性,populateBean 填充屬性
  3. 通過 各種 Aware 接口聲明了依賴關系,則會注入 Bean 對容器基礎設施層面的依賴,包括 BeanNameAware、BeanFactoryAware 和 ApplicationContextAware 分别注入 BeanID, BeanFactory 或者 ApplicationContext。
  4. 調用 BeanPostProcessor 的前置初始化方法 postProcessBeforeInitialization
  5. 如果實作了 InitializingBean 接口,會調用 afterProperties 方法。
  6. 調用 Bean 自定義的 init 方法,initializeBean 調用 xml 的 init方法
  7. 調用 BeanPostprocessor 的字尾初始方法 postProcessAfterInitialization。
  8. 建立過程完畢。

Spring 是如何解決單例的循環依賴問題的呢?

Spring 采用的三級緩存解決了單例的循環依賴問題。

三級緩存:

Spring 源碼 DefaultSingletonBeanRegistry.java 中:

To be called for eager registration of singletons, e.g. to be able to  * resolve circular references.  * @param beanName the name of the bean  * @param singletonFactory the factory for the singleton object  */ protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {  Assert.notNull(singletonFactory, "Singleton factory must not be null");  synchronized (this.singletonObjects) {   // 一級緩存執行個體化 bean 中不包含 正建立的 beanif (!this.singletonObjects.containsKey(beanName)) {       // 三級緩存中添加    this.singletonFactories.put(beanName, singletonFactory);       // 二級緩沖删除    this.earlySingletonObjects.remove(beanName);    this.registeredSingletons.add(beanName);   }  } }

AbstractBeanFactory.doGetBean()

getSingleton 可以這樣了解:

  1. 先從一級緩沖中看有沒有建立好的 bean ,有就直接傳回。
  2. 如果沒有,那麼從二級緩存中看有沒有建立 半成品的 Bean,如果有,直接傳回
  3. 如果沒有,從三級緩存中看下有沒有建立過程中的 bean,還沒有 那麼通過 singletonFactory.getObject 最後到 createBean 建立。

Spring 是怎麼解決單例setter注入循環依賴的?

  • Spring是通過遞歸的方式擷取目标bean及其所依賴的bean的;
  • Spring執行個體化一個bean的時候,是分兩步進行的,首先執行個體化目标bean,然後為其注入屬性

setter 注入是屬性注入和構造器注入不一樣,spring初始化是先建立bean ,然後注入屬性的。單例 的setter采用三級緩存各自拿到各自的屬性引用,然後再屬性注入,最後各自完成執行個體化,不存在循環等待死鎖的問題。

場景:A 依賴 B,B  依賴 A。

假設建立 A 對象的時候進入 getSingleton 方法。建立 B 的時候進入了個 doCreateBean 方法,在建立 B 還沒建立完過程中,會在三級緩存 singletonFactories 先放一個 B,此時,如果建立  A 對象時,一級緩存沒有B,從二級緩存找,二級緩存沒有,從三級别緩存中找到就可以直接傳回,并将自身A放入一級緩存中。

此時 B 在初始化過程中,從一級緩存中取到了A,這樣B就拿到了A的引用,這樣也B也就在拿到A的過程中完成了初始化。

歡迎關注公衆号:程式員開發者社群

spring 循環依賴_Spring 是如何解決循環依賴的?Spring 是如何解決循環依賴的?

繼續閱讀