天天看點

Spring是如何解決循環依賴的?這種設計方案簡直絕了!

作者:程式猿怪咖

全文都是Spring解決循環依賴幹貨,建議關注收藏,然後打開源碼結合源碼看,不然會頭暈.

Spring是如何解決循環依賴的?這種設計方案簡直絕了!

1 什麼是循環依賴?

在Spring中的循環依賴,簡單的來說加入我們現在有A、B兩個個對象,示例如下:

@Bean
public class A {
  @Autowire
  private B b;
}


@Bean
public class B {
  @Autowire
  private A a;
}           

假如Spring沒有幫我們解決循環依賴,看一下會出現什麼情況?

建立對象A-->處理A的依賴B-->建立對象B-->處理B的對象A-->建立對象A-->處理A的依賴B......

從上面的示例可以看出對象的依賴注入就進入到了死循環,這樣是不是很好的了解了什麼是循環依賴。

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

對于循環依賴,其實Spring早就為我們考慮到了并且解決了這個問題,這就是Java中Spring的強大之處了。

其實Spring解決循環依賴的方案就是:三級緩存機制

1、一級緩存【singletonObiects】:用來儲存執行個體化、注入、初始化完成的bean執行個體

2、二級緩存【earlySingletonObject】:用來儲存執行個體化完成的bean執行個體

3、三級緩存【singletonFactories】:用來儲存bean建立工廠,便于後面擴充有機會建立代理對象。

先用一張邏輯圖來了解一下Spring的三級緩存:

Spring是如何解決循環依賴的?這種設計方案簡直絕了!

我們來了解一下Spring的三級緩存解決循環依賴:

1、建立A對象先去一級緩存中擷取執行個體A,擷取不到,然後就建立A并把A放入到三級緩存中。

2、建立A依賴注入了B,又去建立B,同樣去一級緩存中擷取不到B,于是就建立B并放入三級緩存中。

2、這時B依賴A,從三級緩存中擷取到了A,并把A放入二級緩存中;這時B就能初始化成功了,然後把B放入到一級緩存中。

3、這時因在二級緩存中能擷取到A,是以A能初始化成功,并把A放入到一級緩存中。

至此Spring的循環依賴就解決完了。

3 Spring解決循環依賴源碼分析

1、首先啟動Spring容器,建立A執行個體時,來到 AbstractBeanFactory.doGetBean()方法,走一級緩存中拿A對象,當然這裡時肯定沒有拿到對象的

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
    String beanName = this.transformedBeanName(name);
  //先去一級緩存拿對象
    Object sharedInstance = this.getSingleton(beanName);
    Object beanInstance;
  //沒拿到
    if (sharedInstance != null && args == null) {
        if (this.logger.isTraceEnabled()) {
            if (this.isSingletonCurrentlyInCreation(beanName)) {
                this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
            } else {
                this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }

        beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
    } ....//這裡省略了else代碼,後續我們分析的時候貼出來           

2、直接來到建立擷取單例執行個體的位置

....//有代碼省略
if (mbd.isSingleton()) {
  //進入這個方法
    sharedInstance = this.getSingleton(beanName, () -> {
        try {
      //mbd這個參數時一個方法的lamda表達式,下面會調用這裡
            return this.createBean(beanName, mbd, args);
        } catch (BeansException var5) {
            this.destroySingleton(beanName);
            throw var5;
        }
    });
    beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
....//有代碼省略           

3、到了 DefaultSingletonBeanRegistry.getSingleton() 方法

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized(this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }

            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }

            this.beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = this.suppressedExceptions == null;
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet();
            }

            try {
              //這裡就調用了上面說到的lamda表達式方法
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            } catch (IllegalStateException var16) {
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw var16;
                }
            } catch (BeanCreationException var17) {
                BeanCreationException ex = var17;
                if (recordSuppressedExceptions) {
                    Iterator var8 = this.suppressedExceptions.iterator();

                    while(var8.hasNext()) {
                        Exception suppressedException = (Exception)var8.next();
                        ex.addRelatedCause(suppressedException);
                    }
                }

                throw ex;
            } finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }

                this.afterSingletonCreation(beanName);
            }

            if (newSingleton) {
                this.addSingleton(beanName, singletonObject);
            }
        }

        return singletonObject;
    }
}           

4、來到了 AbstractAutowireCapableBeanFactory.createBean() 方法。

public <T> T createBean(Class<T> beanClass) throws BeansException {
    RootBeanDefinition bd = new RootBeanDefinition(beanClass);
    bd.setScope("prototype");
    bd.allowCaching = ClassUtils.isCacheSafe(beanClass, this.getBeanClassLoader());
    //跳進去createBean()
  return this.createBean(beanClass.getName(), bd, (Object[])null);
}           
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    if (this.logger.isTraceEnabled()) {
        this.logger.trace("Creating instance of bean '" + beanName + "'");
    }

    RootBeanDefinition mbdToUse = mbd;
    Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    try {
        mbdToUse.prepareMethodOverrides();
    } catch (BeanDefinitionValidationException var9) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9);
    }

    Object beanInstance;
    try {
        beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
        if (beanInstance != null) {
            return beanInstance;
        }
    } catch (Throwable var10) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);
    }

    try {
      //進入到這裡,建立執行個體對象
        beanInstance = this.doCreateBean(beanName, mbdToUse, args);
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Finished creating instance of bean '" + beanName + "'");
        }

        return beanInstance;
    } catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {
        throw var7;
    } catch (Throwable var8) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);
    }
}           

5、還是AbstractAutowireCapableBeanFactory.doCreateBean()方法,這裡先建立并獲得執行個體對象

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
    }

    if (instanceWrapper == null) {
      //建立執行個體
        instanceWrapper = this.createBeanInstance(beanName, mbd, args);
    }

  //獲得執行個體
    Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }
  .....//源碼省略           

6、同樣是AbstractAutowireCapableBeanFactory.doCreateBean()方法,然後來到了這裡,放入bean到三級緩存的代碼部分

....//省略源碼
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
    if (this.logger.isTraceEnabled()) {
        this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
    }

  //放入三級緩存
    this.addSingletonFactory(beanName, () -> {   
        return this.getEarlyBeanReference(beanName, mbd, bean);
    });
}

Object exposedObject = bean;
......//省略源碼           

7、繼續AbstractAutowireCapableBeanFactory.addSingletonFactory(....)方法,首先判斷一級緩存有無對應執行個體(此時沒有),接着将傳入的 () -> getEarlyBeanReference(beanName, mbd, bean) 放到三級緩存 singletonFactories 中,這時候三級緩存就有對象了,此時的對象隻是一個 帶有方法

() -> getEarlyBeanReference(beanName, mbd, bean) 的 objectFactory對象

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    synchronized(this.singletonObjects) {
      //一級緩存,單例緩存
        if (!this.singletonObjects.containsKey(beanName)) {
          //三級緩存
            this.singletonFactories.put(beanName, singletonFactory);
          //二級緩存
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }

    }
}           

8、放入三級緩存後,回到AbstractAutowireCapableBeanFactory.doCreateBean()方法,這裡就開始依賴注入了

....//代碼省略
Object exposedObject = bean;

try {
  //依賴注入
    this.populateBean(beanName, mbd, instanceWrapper);
    exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
    if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
        throw (BeanCreationException)var18;
    }

    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
}
...//代碼省略           

9、然後對屬性B注入,又回到AbstractBeanFactory.doGetBean()方法建立A的步驟去建立對象B,也是走到依賴注入這裡,這時候需要對B的屬性A進行注入,是以又來到建立A的階段 AbstractBeanFactory.doCreateBean()方法,不過此時的 三級緩存 singletonFactories 已經A了。

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
        String beanName = this.transformedBeanName(name);
  //回到了這裡,這次是走三級緩存中拿到了A
        Object sharedInstance = this.getSingleton(beanName);
        Object beanInstance;
        if (sharedInstance != null && args == null) {
            if (this.logger.isTraceEnabled()) {
                if (this.isSingletonCurrentlyInCreation(beanName)) {
                    this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
                } else {
                    this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }

            beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
  ...//代碼省略           

10、進入AbstractBeanFactory.getSingleton()方法,裡面就是處理的去三級緩存拿資料的邏輯。

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //走一級緩存拿A
  Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
        //二級緩存中拿A
      singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
          //加鎖,放棄多線程進入建立多執行個體
            synchronized(this.singletonObjects) {
              //再次拿一級緩存
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                  //再次拿二級緩存
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) {
                      //走三級緩存中擷取上一次存入的objectFactory
                        ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                          //執行前面提到過的lamda表達式方法
                            singletonObject = singletonFactory.getObject();
                         	//放入耳機緩存
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            //移除一級緩存
                          this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
        }
    }

    return singletonObject;
}           

11、繼續來到AbstractBeanFactory.getSingleton()方法點進去,B拿到A進行依賴注入,繼續 AbstractAutowireCapableBeanFactory.createBean() 方法,再進入到DefaultSingletonBeanRegistry.getSingleton()方法,此時B一級拿到了。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized(this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }

            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }

            this.beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = this.suppressedExceptions == null;
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet();
            }

            try {
                singletonObject = singletonFactory.getObject();
              //這裡就能看到拿到了B對象的執行個體
                newSingleton = true;
            } catch (IllegalStateException var16) {
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw var16;
                }
            } catch (BeanCreationException var17) {
                BeanCreationException ex = var17;
                if (recordSuppressedExceptions) {
                    Iterator var8 = this.suppressedExceptions.iterator();

                    while(var8.hasNext()) {
                        Exception suppressedException = (Exception)var8.next();
                        ex.addRelatedCause(suppressedException);
                    }
                }

                throw ex;
            } finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }

                this.afterSingletonCreation(beanName);
            }

            if (newSingleton) {
                this.addSingleton(beanName, singletonObject);
            }
        }

        return singletonObject;
    }
}           

12、繼續 AbstractAutowireCapableBeanFactory.createBean() 方法,将B放入一級緩存,同時移除二級緩存和三級緩存中的B,此時B可建立完成,最後傳回B給A,A也就完成注入了,最後把A放入一級緩存,移除二級緩存和三級緩存中的A。至此A也建立好了。

....//代碼省略
if (recordSuppressedExceptions) {
            this.suppressedExceptions = null;
        }

        this.afterSingletonCreation(beanName);
    }

    if (newSingleton) {
      //B放入一級緩存
        this.addSingleton(beanName, singletonObject);
    }
}

return singletonObject;
...//源碼省略           

3 Spring為什麼要用三級緩存解決循環依賴?

這裡簡短的提一下,當A類使用注解@Transactional時,如果不用三級緩存就解決不了,具體的大家下來再了解一下,這就是為什麼Spring用三級緩存解決循環依賴而不是二級緩存。