從源碼角度解讀Spring循環依賴 --- 三級緩存各自作用

前言

對於循環依賴,我相信讀者無論只是聽過也好,還是有過了解也好,至少都有所接觸。但是我發現目前許多博客對於循環依賴的講解並不清楚,都提到了Spring的循環依賴解決方案是三級緩存,但是三級緩存每一級的作用是什麼,爲什麼要這樣設計三級緩存,很多博客都沒有提到。爲了讓大家能夠更加清晰的理解Spring的循環依賴,下面我便帶領大家從Spring源碼的角度出發,講解Spring循環依賴的整個流程以及其解決方案 —— 三級緩存的作用。

提示

此文章建議讀者先閱讀一下Spring創建bean流程的代碼,這樣再讀這篇文章體會會明顯一些
若是讀者就想知道結論,建議直接從目錄四開始看
若是讀者已經知道Spring創建bean的流程,那也建議直接從目錄四開始看

一、首先說明什麼是循環依賴

比如,現在有兩個類,OrderService和UserService(下面文章中我們簡稱其爲os和us,並且就以這兩個類作爲演示),所謂的Spring循環依賴就是在os中依賴了us,us中依賴了os。按照正常的流程來說:

  1. Spring根據字典序優先創建os的bean,但是容器中沒有os的bean,便創建os的bean
  2. 在創建os的過程中發現需要屬性注入us,然而容器中也沒有us的bean,這時便開始創建us
  3. 創建us的過程中其發現需要屬性注入os,容器中也沒有存放os的bean,就又開始創建os…

如此便進入了死循環中。但是Spring中是否真是如此呢?我們來代碼演示一下:
這裏是 os類,其中依賴了us

@Component
public class OrderService {
   
   
	@Autowired
	private UserService userService;

	public OrderService(){
   
   
		System.out.println("start orderService");
	}
}

這裏是 us類,其中依賴了os

@Component
public class UserService {
   
   
	@Autowired
	private OrderService orderService;

	public UserService(){
   
   
		System.out.println("start userService");
	}

}

這裏是測試類

public class Test {
   
   
	public static void main(String[] args) throws Exception {
   
   
		AnnotationConfigApplicationContext ac =
				new AnnotationConfigApplicationContext();
		ac.register(Appconfig.class);
		ac.refresh();
		//關閉循環依賴
//		ac.setAllowCircularReferences(false);

		System.out.println(ac.getBean(OrderService.class));
		System.out.println(ac.getBean(UserService.class));

	}
}

運行結果如下:

我們可以看見os和us都是正常打印,並沒有報錯,說明Spring是做了 某些處理 使其允許循環依賴。其實Spring是提供了關閉循環依賴的api的,比如上面測試類代碼中註釋掉的那句話,我們打開那個註釋,再運行一次。
在這裏插入圖片描述
可以看見直接運行報錯,報錯信息大家可以自己下去測試看看。
這裏再說明有兩種情況下Spring是不支持循環依賴的,原因大家可以自行了解一下。




  1. 當bean的作用域是原型的時候
  2. 當以構造器的形式注入的時候

下面文章,我就來詳細講解 某些處理 到底是什麼處理。

二、循環依賴三級緩存以及整個流程介紹

首先給三級緩存在Spring中到底是哪三級,在 DefaultSingletonBeanRegistry 類中:

	/** Cache of singleton objects: bean name to bean instance. */
	// 一級緩存,可稱爲單例池,存放創建好的單例bean的map beanName - bean
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name to ObjectFactory. */
	// 三級緩存,存放的結構是 beanName - ObjectFactory
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** Cache of early singleton objects: bean name to bean instance. */
	// 二級緩存,存放的結構是 beanName - bean
	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

因爲Spring的循環依賴解決只是bean的生命週期中的一個很小的部分,其歸屬的部分是屬性填充時期,意思就是循環依賴是在屬性填充時期發生並解決的。bean生命週期大概如下:

  1. 推斷構造方法
  2. 實例化對象
  3. 屬性填充
  4. 生命週期回調初始化方法

爲了讓大家能夠更加清晰的理解Spring的循環依賴,這裏先用文字描述一下,Spring創建bean解決循環依賴的的大概流程(下面的源碼敘述就圍繞這個流程展開

  1. Spring優先創建os,在調用getSingleton 獲取os的bean的時候,發現單例池中沒有,所以會createBean,並將os放入正在創建的容器中;
  2. 進行os對象的實例化,然後將os放入三級緩存中,接着對os進行屬性填充,執行某個後置處理器
    方法完成屬性填充;
  3. 屬性填充時發現os中的屬性是us,就會取getBean,但是拿不到us(還未創建),所以會createBean創建us的bean,並將us放入正在創建的容器中;
  4. 進行us對象的實例化,然後將us放入三級緩存中,接着對us進行屬性填充;
  5. 屬性填充時,發現us中的屬性是os,但是得到os的bean爲空,並且os現在是屬於在正在創建的,所以再次調用getSingleton 會從三級緩存中得到os;
  6. 到此us屬性填充完畢,us這個bean存入單例池(一級緩存),方法棧返回,將us注入到os中,完成循環依賴。

到這裏我相信大家可能會有如下幾個疑問:

  1. 爲什麼要設置三級緩存?各自作用是什麼?
  2. 第三級緩存的value值類型爲什麼和前兩級不一樣?
  3. 在上述流程中的步驟2說的某個後置處理器是哪個後置處理器?
  4. 在上述流程中的步驟5中,調用getSingleton 如何從三級緩存中獲取bean?

三、源碼敘述Spring循環依賴

將上面流程轉化爲具體的源碼調用,如下:
1、流程的第一步。

Spring優先創建os,在調用getSingleton 獲取os的bean的時候,發現單例池中沒有,所以會createBean,並將os放入正在創建的容器中。

(1)代碼調用如下:

ac.refresh();

//這個方法的功能之一就是完成類的實例化和屬性注入
finishBeanFactoryInitialization(beanFactory);

//實例化所有的非lazy的單例bean
beanFactory.preInstantiateSingletons();

(2)進入這個 preInstantiateSingletons() 方法中(一些不怎麼必要的邏輯,我就直接省略了),在這個方法裏面會得到所有的beanDefinition(這個東西就是用於描述一個bean的,大家可以自己去了解一下,這裏不做展開)的名稱,判斷這個bean是否是FactoryBean或者是一個普通的bean,這裏我們的os是一個普通的bean(一般來說都是一個普通的bean),進入else,調用getBean(String) 方法。

@Override
public void preInstantiateSingletons() throws BeansException {
   
   
   //這裏得到所有的 bd名字
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   // Trigger initialization of all non-lazy singleton beans...
   // 這裏就遍歷所有的bd,然後進行所有非惰性單例的bean的初始化
   for (String beanName : beanNames) {
   
   
      // 根據bd名字看是否需要合併獲取其 bd
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      //如果這個bd不是抽象的,是單例的,不是lazy的,那就表示其現在可以進行初始化
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
   
   
         //如果這個bean是一個 FactoryBean
         if (isFactoryBean(beanName)) {
   
   
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            if (bean instanceof FactoryBean) {
   
   
               ...
            }
         }
         // 否則是一個普通的bean
         else {
   
   
            // 根據beanName獲取一個bean。
            getBean(beanName);
         }
      }
   }
    ...
}

(3)進入 getBean(String) 方法,裏面調用的的是doGetBean 方法

@Override
public Object getBean(String name) throws BeansException {
   
   
   return doGetBean(name, null, null, false);
}

(4)進入 doGetBean 方法,在這個方法中會調用 getSingleton(String) 方法!!!!注意這個getSingleton(String) 方法,很重要,這個方法就是解決循環依賴的根本方法。第一次調用 getSingleton(String) 得到os的bean爲null,便會再次調用重載的 getSingleton(String, ObjectFactory) 方法。

protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {
   
   

   // 可以理解爲驗證bean的名字是否合法,若是合法則將bd map中的key作爲beanName
   // 在獲取factoryBean的時候 若是加上 & 則是獲取FactoryBean對象本身的bean,不加 & 則是獲取返回的對象的bean
   String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   // getSingleton !!!!!  重點方法!!!!
   // 這裏就從 singletonObjects(單例池) 容器中直接拿,下面代碼中還會調用其重載的 getSingleton
   // 第一次獲取的肯定是null
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
   
   
       ...
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   else {
   
   
    ...
      if (!typeCheckOnly) {
   
   
         markBeanAsCreated(beanName);
      }

      try {
   
   
         RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         // Guarantee initialization of beans that the current bean depends on.
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
   
   
            ...
         }

         // Create bean instance.
         if (mbd.isSingleton()) {
   
   
            // 這裏再次調用 getSingleton (重載的)
            sharedInstance = getSingleton(beanName, () -> {
   
   
               // 這個lambda表達式的邏輯就是爲了創建一個單例bean
               try {
   
   
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
   
   
                  destroySingleton(beanName);
                  throw ex;
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }

         else if (mbd.isPrototype()) {
   
   
           ...
         }
      }
      catch (BeansException ex) {
   
   
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }

   // Check if required type matches the type of the actual bean instance.
   if (requiredType != null && !requiredType.isInstance(bean)) {
   
   
      ...
   }
   return (T) bean;
}

(4.1)這裏給出 getSingleton(String) 方法邏輯,可以看到參數2Spring直接給的true,在 getSingleton(String , boolean) 方法中,第一次調用會返回null。

@Override
@Nullable
public Object getSingleton(String beanName) {
   
   
	// 參數2直接給的true
   return getSingleton(beanName, true);
}


@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   
   
   // Quick check for existing instance without full singleton lock
   // 首先從一級緩存 singletonObjects 單例池直接獲取,singletonObjects就是bean的單例池
   Object singletonObject = this.singletonObjects.get(beanName);

   // 如果從一級緩存 單例池中獲取的bean爲空,並且該bean正在被創建
   // 第一次運行進來第二個條件肯定不滿足,不進入if,直接返回 singletonObject
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
   
   
      // 從二級緩存中獲取
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
   
   
         synchronized (this.singletonObjects) {
   
   
            // Consistent creation of early reference within full singleton lock
            // 再次從一級緩存中獲取
            singletonObject = this.singletonObjects.get(beanName);
            // 若是一次緩存中沒有
            if (singletonObject == null) {
   
   
               // 從二級緩存中獲取
               singletonObject = this.earlySingletonObjects.get(beanName);
               // 若是二級緩存中也沒有
               if (singletonObject == null) {
   
   
                  // 那就從三級緩存中獲取
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  // 若是三級緩存中拿到了
                  if (singletonFactory != null) {
   
   
                     singletonObject = singletonFactory.getObject();
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

(4.2)這裏給出 getSingleton(String, ObjectFactory) 方法邏輯,裏面的beforeSingletonCreation(String) 方法就將當前正在創建bean存入了表示正在創建的集合 singletonsCurrentlyInCreation 中,即將os存入其中。singletonObject = singletonFactory.getObject(); 這個這句話就得到創建好的bean,但是singletonFactory是哪裏來的呢?他其實是由外部的lambda表達式實現的。在外部的lambda表達式中就調用了 createBean(…) 這個方法去創建了一個單例的bean。

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
      if (singletonObject == null) {
   
   
         if (this.singletonsCurrentlyInDestruction) {
   
   
            ...
         }
         if (logger.isDebugEnabled()) {
   
   
            ...
         }
         // 將當前beanName存入正在創建bean的set集合中
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
   
   
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
   
   
            // 這個getObject() 的邏輯就是該方法外部的lambda 表達式
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
   
   
            ...
         }
         finally {
   
   
            ...
            afterSingletonCreation(beanName);
         }
         // 將創建好的單例bean存入單例池中
         if (newSingleton) {
   
   
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

(4.2.1)這裏給出beforeSingletonCreation(String)的邏輯
其作用就是將該beanName放入了這個表示正在創建的集合 singletonsCurrentlyInCreation中

protected void beforeSingletonCreation(String beanName) {
   
   
   //這裏完成的功能就是,判斷當前檢查中是否包含該bean,並且判斷該bean是否在正在創建,注意這裏是add
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
   
   
      throw new BeanCurrentlyInCreationException(beanName);
   }
}

以上代碼就是流程的第一步:
Spring優先創建os,在調用getSingleton 獲取os的bean的時候,發現單例池中沒有,所以會createBean,並將os放入正在創建的容器中;

2、流程的第二步。

進行os對象的實例化,然後將os放入三級緩存中,接着對os進行屬性填充,執行某個後置處理器方法完成屬性填充;

(4.3)這裏給出getSingleton(String, ObjectFactory) 參數2的lambda表達式邏輯
在(4.2)中有這樣一句代碼getObject() ,由於lambda表達式的異步性,所以當調用getObject() 方法時纔會執行lambda表達式,在lambda表達式中調用了一個方法 createBean(beanName, mbd, args) 而createBean 的返回值就是 getObject()所得到的對象。在 createBean 中又繼續調用了doCreateBean 方法得到了一個完整的bean。

// 這個getObject() 的邏輯就是該方法外部的lambda 表達式
singletonObject = singletonFactory.getObject();

// lambda表達式如下
() -> {
   
   
   // 這個lambda表達式的邏輯就是爲了創建一個單例bean
   try {
   
   
      return createBean(beanName, mbd, args);
   }
   catch (BeansException ex) {
   
   
      destroySingleton(beanName);
      throw ex;
   }
}

//其中 createBean(beanName, mbd, args) 方法邏輯如下
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   
   

   if (logger.isTraceEnabled()) {
   
   
      ...
   }
   RootBeanDefinition mbdToUse = mbd;

   // Make sure bean class is actually resolved at this point, and
   // clone the bean definition in case of a dynamically resolved Class
   // which cannot be stored in the shared merged bean definition.
   // 從beanDefinition對象中獲取出來bean的類型,因爲實例化對象就需要類
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
   
   
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }

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

   try {
   
   
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      // 第一次調用後置處理器 --- 與aop有關
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      // 90%的情況這裏的bean就是爲空,因爲這裏是做aop的屬性設置
      if (bean != null) {
   
   
         return bean;
      }
   }
   catch (Throwable ex) {
   
   
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
   }

   try {
   
   
      // 這裏就會來進行bean的創建 將beanName,bd,和一些參數傳入開始進行bean的創建
      // beanInstance就是實例化好的一個完整的bean
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {
   
   
         logger.trace("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
   }
   catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
   
   
      // A previously detected exception with proper bean creation context already,
      // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
      throw ex;
   }
   catch (Throwable ex) {
   
   
      throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
   }
}

(5)這裏給出 doCreateBean(beanName, mbdToUse, args) 方法的邏輯
在這個方法中,在執行 createBeanInstance(beanName, mbd, args) 方法的時候會進行實例化os對象,裏面完成了推斷構造方法 和 實例化對象,但是此時並未注入屬性。後面初始化了一個 boolean類型的值 earlySingletonExposure,因爲此時os是單例的,並且Spring是允許循環依賴的,並且os也在正在創建的那個集合中,所以此時這個boolean值就爲true。如此便會進入下面的那個if之中,調用addSingletonFactory() 方法(查看5.1)將os以ObjectFactory的形式存入了三級緩存中。後面便調用了 populateBean(beanName, mbd, instanceWrapper) 方法完成了屬性注入。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   
   

   // Instantiate the bean.
   // 這裏開始實例化bean
   BeanWrapper instanceWrapper = null;
   // 如果是單例的
   if (mbd.isSingleton()) {
   
   
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
   
   
      // 實例化對象,裏面第二次調用後置處理器 --- 這裏面完成了推斷構造方法 和 實例化對象(還未注入屬性!!!!)
      // 得到的 instanceWrapper 就是實例化好的對象的包裝類
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   // 這裏就通過bean的包裝類得到了該bean的實例和類型
   Object bean = instanceWrapper.getWrappedInstance();
   Class<?> beanType = instanceWrapper.getWrappedClass();
   if (beanType != NullBean.class) {
   
   
      mbd.resolvedTargetType = beanType;
   }

   // Allow post-processors to modify the merged bean definition.
   synchronized (mbd.postProcessingLock) {
   
   
      if (!mbd.postProcessed) {
   
   
         ...
      }
   }

   // Eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like BeanFactoryAware.
   // 判斷是否允許進行循環依賴並且提前暴露這個單例bean,注意這裏很重要,
   // 這個boolean值與 getSingleton(String, boolean) 方法是密切相關的
   // 條件1:該bean是否單例
   // 條件2:該類的 allowCircularReferences 屬性,這個屬性默認爲true,那就是直接體現Spring是默認支持循環依賴的
   // 條件3:該bean是否是正在創建的(beanName是否在正在創建的容器之中)
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {
   
   
      ...
      // 第四次調用後置處理器,判斷是否需要進行 AOP
      // 參數2是一個ObjectFactory --- 對象工廠,使用的是lambda表達式
      // 這裏提前暴露一個對象工廠,而不是一個bean對象!!!
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
   
   
      // 這裏面進行屬性填充,即常說的自動注入
      populateBean(beanName, mbd, instanceWrapper);
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   catch (Throwable ex) {
   
   
      ...
   }

   if (earlySingletonExposure) {
   
   
      ...
   }

   // Register bean as disposable.
   try {
   
   
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
   
   
      ...
   }

   return exposedObject;
}

(5.1)這裏給出 addSingletonFactory(String, ObjectFactory)的邏輯
此時就將os以ObjectFactory的形式存入了三級緩存中。

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   
   
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
   
   
      // 若是一級緩存中沒有這個bean,表示這個bean還沒有創建完畢
      if (!this.singletonObjects.containsKey(beanName)) {
   
   

         // 三級緩存中添加該 對象工廠
         this.singletonFactories.put(beanName, singletonFactory);

         // 二級緩存中移除該bean,這裏爲什麼要移除
         // 我認爲這裏移除的原因有兩點:
         // 1、就是爲了讓程序在調用 getSingleton(String, boolean) 方法的時候,進入第二個if,就是同步代碼塊中。
         // 2、從二級緩存中移除一箇舊的bean,便於三級緩存重新生產一個新(重新進行aop等操作)對象
         this.earlySingletonObjects.remove(beanName);

         // 將該beanName存放到表示保存已經註冊好的bean的集合中
         this.registeredSingletons.add(beanName);
      }
   }
}

5.2、這裏給出lambda表達式() -> getEarlyBeanReference(beanName, mbd, bean)中方法的邏輯
這個lambda的調用時機是在 getSingleton(String) 這個方法裏面
其與aop相關,所以Spring其實是很早就進行了aop的,而不只是生命週期的那個時間段(請注意這句話)。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   
   
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   
   
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
   
   
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
   
   
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

6、這裏給出populateBean(beanName, mbd, instanceWrapper) 方法的邏輯
在這個方法中首先會執行InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation()方法。實際上我們可以自己實現InstantiationAwareBeanPostProcessor接口,然後重寫postProcessAfterInstantiation()方法,讓其返回false,便可以對指定的bean設置其不允許循環依賴。
後面代碼中最重要的便是 InstantiationAwareBeanPostProcessor這個後置處理器的 postProcessProperties() 方法調用,這個方法就完成了屬性注入。其實現類 AutowiredAnnotationBeanPostProcessor 便完成了了 @Autowired 註解的實現,另外一個實現類 CommonAnnotationBeanPostProcessor 完成了 @Resources 註解的實現。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   
   
   if (bw == null) {
   
   
      if (mbd.hasPropertyValues()) {
   
   
         ...
      }
      else {
   
   
         // Skip property population phase for null instance.
         return;
      }
   }

   // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
   // state of the bean before properties are set. This can be used, for example,
   // to support styles of field injection.
   // 判斷要不要進行屬性注入。
   // 我們自己可以實現 InstantiationAwareBeanPostProcessor 這個接口,
   // 重寫其中 postProcessAfterInstantiation() 方法使其返回false,則可以不再進行屬性注入
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   
   
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
   
   
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
   
   
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
   
   
               return;
            }
         }
      }
   }

   // pvs是表示你有沒有給我的屬性傳入值
   // 比如當使用xml的形式時,有ref指定該屬性需要傳入的值是什麼,但是 @Autowired 沒法指定值所以會得到null
   // 正因爲是null 所以其開始進行屬性自動注入
   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

   // 得到該bean的自動注入模式,@Autowired 的自動注入模式爲 0
   int resolvedAutowireMode = mbd.getResolvedAutowireMode();

   // 判斷該注入模式是byName還是byType,所以@Autowired 不會進入這個判斷
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
   
   
      ...
   }

   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

   PropertyDescriptor[] filteredPds = null;
   if (hasInstAwareBpps) {
   
   
      if (pvs == null) {
   
   
         pvs = mbd.getPropertyValues();
      }
      // 在 getBeanPostProcessors() 中會得到6個 bean後置處理器
      // 其中一個叫 CommonAnnotationBeanPostProcessor 這個bean後置處理器就是處理 @Resource 註解的
      // 還有一個叫 AutowiredAnnotationBeanPostProcessor 這個bean後置處理器就是處理 @Autowired 註解的
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
   
   
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
   
   
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // 這裏就是執行 對應後置處理器的重寫方法
            // @Autowired 註解便會執行 AutowiredAnnotationBeanPostProcessor 這個後置處理器的重寫方法
            /** AutowiredAnnotationBeanPostProcessor後置處理器的這個方法就是完成屬性填充 */
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
   
   
              ...
            }
            pvs = pvsToUse;
         }
      }
   }
   if (needsDepCheck) {
   
   
      ...
   }

   if (pvs != null) {
   
   
      ...
   }
}

以上代碼就是流程的第二步:
進行os對象的實例化,然後將os放入三級緩存中,接着對os進行屬性填充,執行某個後置處理器
方法完成屬性填充;

上述流程中的第三,四,五步其實就是在循環做上述任務,第六步時屬性已經填充完畢,循環依賴早已解決

如果你仔細觀看了上述文章並且有結合Spring源碼進行閱讀,你就會發現,getSingleton(String) 與 addSingletonFactory(String, ObjectFactory) 這兩個方法尤爲重要,他們就是Spring解決循環依賴的根本邏輯。

四、重點說明getSingleton(String) 和 addSingletonFactory(String, ObjectFactory)

在說明這兩個方法之前,再總結一下循環依賴的流程:

  1. get os的bean,調用getSingleton(String) 但是爲null;
  2. 將os放入表示正在創建的集合中;
  3. 實例化os的對象;
  4. 調用addSingletonFactory(String, ObjectFactory) 將os所對應的 ObjectFactory放入三級緩存;
  5. os對象進行屬性填充;
  6. os屬性填充時發現屬性是us,調用 getSingleton(String) 獲取us的bean,但是爲null;
  7. 將us放入表示正在創建的集合中;
  8. 實例化us的對象;
  9. 調用addSingletonFactory(String, ObjectFactory) 將us所對應的 ObjectFactory放入三級緩存;
  10. us進行屬性填充;
  11. us進行屬性填充時,發現屬性是os,就調用 getSingleton(String) 獲取us的bean,這是能夠獲取到,us屬性填充完畢;
  12. us初始化完成,方法棧返回,os屬性填充完畢,os初始化完成。

爲了方便說明,下面再次給出 addSingletonFactory(String, ObjectFactory) 方法源碼

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   
   
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
   
   
      // 若是一級緩存中沒有這個bean,表示這個bean還沒有創建完畢
      if (!this.singletonObjects.containsKey(beanName)) {
   
   

         // 三級緩存中添加該 對象工廠
         // 這裏提前暴露一個對象工廠,而不是一個bean對象
         this.singletonFactories.put(beanName, singletonFactory);

         // 二級緩存中移除該bean,這裏爲什麼要移除
         // 我認爲這裏移除的原因有兩點:
         // 1、就是爲了讓程序在調用 getSingleton(String, boolean) 方法的時候,進入第二個if,就是同步代碼塊中。
         // 2、從二級緩存中移除一箇舊的bean,便於三級緩存重新生產一個新(重新進行aop等操作)對象
         this.earlySingletonObjects.remove(beanName);

         // 將該beanName存放到表示保存已經註冊好的bean的集合中
         this.registeredSingletons.add(beanName);
      }
   }
}

其中參數2的ObjectFactory,是由一個lambda表達式傳入的,下面給出這個lambda表達式的源碼
這個lambda表達式中的那個後置處理器完成的一個功能就是進行了aop!看到這,我相信有些讀者應該已經知道了第三級緩存value值爲什麼是一個 ObjectFactory了,如果還不知道,也沒事,下面會解釋。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   
   
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   
   
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
   
   
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
   
   
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

再說明 getSingleton(String) 方法,這裏再次給出其方法源碼
這個方法其實也沒有什麼難懂的邏輯,看看註釋也就知道他在幹嘛了。

@Override
@Nullable
public Object getSingleton(String beanName) {
   
   
   return getSingleton(beanName, true);
}


protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   
   
   // Quick check for existing instance without full singleton lock
   // 首先從一級緩存 singletonObjects 單例池直接獲取,singletonObjects就是bean的單例池
   Object singletonObject = this.singletonObjects.get(beanName);

   // 如果從一級緩存 單例池中獲取的bean爲空,並且該bean正在被創建
   // 第一次運行進來第二個條件肯定不滿足,不進入if,直接返回 singletonObject

   // 但是如果有循環依賴的情況,這個條件就會滿足!!!!
   // 如下代碼就是Spring解決循環依賴的實現過程
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
   
   
      // 從二級緩存中獲取
      singletonObject = this.earlySingletonObjects.get(beanName);
      // 如果一級緩存中爲空,並且表示允許提前引用(這個條件從getBean的流程過來,Spring直接給的true)
      // allowEarlyReference在這裏直接默認爲true,表示允許提前引用???
      // 我覺得這個提前引用的意思就是(注意這個if的位置):因爲循環引用的原因,導致這個時候的bean還是一個不完整的,
      // 但是一個不完整的bean怎麼能夠給別人使用呢,所以這裏需要進行一個判斷,是否允許一個不完整的bean提供給別人
      // 當一個不完整的bean給被別人使用的時候,最後還是得讓其變得完整,所以這裏使用了ObjectFactory。
      // 由於循環依賴的特殊性,所以這裏爲true。這裏也可以作爲Spring允許循環依賴的源碼級別證據之一。
      if (singletonObject == null && allowEarlyReference) {
   
   
         synchronized (this.singletonObjects) {
   
   
            // Consistent creation of early reference within full singleton lock
            // 再次從一級緩存中獲取
            singletonObject = this.singletonObjects.get(beanName);
            // 若是一次緩存中沒有
            if (singletonObject == null) {
   
   
               // 從二級緩存中獲取
               singletonObject = this.earlySingletonObjects.get(beanName);
               // 若是二級緩存中也沒有
               if (singletonObject == null) {
   
   
                  // 那就從三級緩存中獲取
                  // 三級緩存存放對象工廠的時機是在屬性注入之前,並且earlySingletonExposure爲true
                  // 所以當有循環依賴的時候,Spring就會從三級緩存中拿到這個不完整的bean,進行屬性注入
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  // 若是三級緩存中拿到了
                  if (singletonFactory != null) {
   
   
                     // 得到 bean實例,注意這個 singletonFactory.getObject()得到bean 是使用lambda表達式完成的。
                     // 而lambda是異步進行的,即調用方法時纔會執行。
                     // 而在這個表達式方法中完成了一個後置處理器的調用才返回了這個bean
                     // 這個後置處理器所完成的任務就是對循環依賴時的aop的解決。
                     singletonObject = singletonFactory.getObject();
                     // 將解決好aop問題的bean實例放入二級緩存中!!!!!
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     // 將該對象工廠從三級緩存中移除,因爲解決好aop問題的bean實例已經存放入二級緩存中
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

這裏說明第三級緩存爲什麼是一個ObjectFactory?
我們通過一個問題來說明

一個普通bean進行aop的過程:
new A -> 執行屬性注入 -> 生命週期回調 -> 判斷aop代理 -> put 一級緩存

當循環依賴時有aop的執行過程:比如這裏有A B兩類的循環依賴,A進行了aop:
A實例化對象(A還是一個簡單對象沒有aop) -> 屬性注入B -> get B -> new B
 -> 注入A(此時A還是一個簡單對象,沒有進行aop),A注入到B -> B put到容器 -> B注入到A
 -> 生命週期回調 -> aop -> A put到容器
------->   可以看到此時的問題就是A是進行了aop的,但是B中的A卻是一個沒有進行aop的簡單對象

所以這裏三級緩存使用ObjectFactory的原因就在這裏:
ObjectFactory 可以對對象進行任意修改,而這裏的使用就是完成了循環依賴情況下的aop的代理的實現。singletonFactory.getObject() 所得到的對象就是上述lambda 表達式中方法getEarlyBeanReference(beanName, mbd, bean) 的返回對象,而這個方法中會調用後置處理器完成aop,這樣便解決了上面所說的問題。

到這裏,我相信很多讀者應該已經知道了三級緩存各自的作用了吧,可能你會問二級緩存不是沒有說嗎?但是這二級緩存的作用和存在的意義讀者可以思考一下,不過也沒關係,下面總結也會提到。

五、總結

這裏的總結也就是回答上面提到的四個問題:

問題1:爲什麼要設置三級緩存,各自的作用是什麼?
Spring設計這三級緩存的原因,很大程度上就是爲了解決循環依賴所帶來的一系列問題
其各自的作用:

一級緩存:單例池,就是爲了存放實例化好的bean

二級緩存:我認爲設置二級緩存的目的是爲了填補空白期,當三級緩存創建好了解決aop問題的bean到這個bean存入一級緩存(單例池)的這個空白期使用。當在多線程情況下,若是沒有這個二級緩存,此時三級緩存已經移除,而一級緩存又沒有存入,就會出現問題。可能有人會問爲什麼不直接使用三級緩存,而要設計一個二級緩存,我認爲是因爲一個效率問題,工廠創建bean還是需要時間,不如先直接把這個解決好aop問題的bean拿出來。

三級緩存:使用ObjectFactory完成了循環依賴情況下的aop的代理問題解決

問題2:第三級緩存的value值爲什麼和前兩級不一樣?

答案已經在問題1的回答裏面了

問題3:在上述流程中的步驟2說的某個後置處理器是哪個後置處理器?

一個叫 CommonAnnotationBeanPostProcessor 這個bean後置處理器就是處理 @Resource 註解的
還有一個叫 AutowiredAnnotationBeanPostProcessor 這個bean後置處理器就是處理 @Autowired 註解的

問題4:在上述流程中的步驟5中,調用getSingleton 如何從三級緩存中獲取bean?

這個問題的答案就在 getSingleton(String) 方法中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章