<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      詳解Spring循環(huán)依賴

      一. 什么是循環(huán)依賴

      循環(huán)依賴,就是兩個或則兩個以上的bean互相依賴對方,最終形成閉環(huán)。比如“A對象依賴B對象,而B對象也依賴A對象”,或者“A對象依賴B對象,B對象依賴C對象,C對象依賴A對象”;類似以下代碼:

      public class A {
          private B b;
      }
      
      public class B {
          private A a;
      }
      

      常規(guī)情況下,會出現(xiàn)以下情況:

      1. 通過構(gòu)建函數(shù)創(chuàng)建A對象(A對象是半成品,還沒注入屬性和調(diào)用init方法)。
      2. A對象需要注入B對象,發(fā)現(xiàn)對象池(緩存)里還沒有B對象(對象在創(chuàng)建并且注入屬性和初始化完成之后,會放入對象緩存里)。
      3. 通過構(gòu)建函數(shù)創(chuàng)建B對象(B對象是半成品,還沒注入屬性和調(diào)用init方法)。
      4. B對象需要注入A對象,發(fā)現(xiàn)對象池里還沒有A對象。
      5. 創(chuàng)建A對象,循環(huán)以上步驟。

      Spring 循環(huán)依賴的場景有兩種:

      1. 構(gòu)造器的循環(huán)依賴。
      2. field 屬性的循環(huán)依賴。

      對于構(gòu)造器的循環(huán)依賴,Spring 是無法解決的,只能拋出 BeanCurrentlyInCreationException 異常表示循環(huán)依賴,所以下面我們分析的都是基于 field 屬性的循環(huán)依賴

      Spring 只解決 scope 為 singleton 的循環(huán)依賴。對于scope 為 prototype 的 bean ,Spring 無法解決,直接拋出 BeanCurrentlyInCreationException 異常。

      二. 解決循環(huán)依賴

      Spring創(chuàng)建Bean的過程中會用到三級緩存:

      // DefaultSingletonBeanRegistry.java
              
      /**
       * 一級緩存,存放可用的成品Bean。
       * 對應(yīng)關(guān)系為 bean name --> bean instance
       */
      private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
          
      /**
       * 二級緩存,存放半成品的Bean,半成品的Bean是已創(chuàng)建對象,但是未注入屬性和初始化。用以解決循環(huán)依賴。
       * 對應(yīng)關(guān)系也是 bean name --> bean instance。
       */
      private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
          
      /**
       * 三級緩存,存的是Bean工廠對象,用來生成半成品的Bean并放入到二級緩存中。用以解決循環(huán)依賴。
       * 對應(yīng)關(guān)系是 bean name --> ObjectFactory
       */
      private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
      

      要了解解決循環(huán)依賴的原理,得從Bean的創(chuàng)建過程說起:

      // AbstractBeanFactory.java
      protected <T> T doGetBean(
      			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly){
          //<1> 從緩存中或者實例工廠中獲取 Bean 對象
      	Object sharedInstance = getSingleton(beanName);
      	if (sharedInstance != null && args == null) {
      		...
      	}
      	else {
      		....
              if (mbd.isSingleton()) {
                  // <3> 將創(chuàng)建好的Bean實例放入一級緩存
                  sharedInstance = getSingleton(beanName, () -> {
                      try {
                          // <2> bean 實例化
                          return createBean(beanName, mbd, args);
                      }
                      catch (BeansException ex) {
                          // Explicitly remove instance from singleton cache: It might have been put there
                          // eagerly by the creation process, to allow for circular reference resolution.
                          // Also remove any beans that received a temporary reference to the bean.
                          // 顯式從單例緩存中刪除 Bean 實例
                          // 因為單例模式下為了解決循環(huán)依賴,可能他已經(jīng)存在了,所以銷毀它。
                          destroySingleton(beanName);
                          throw ex;
                      }
                  });
                  beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
              }
              ...	
      	}
      }
      
      • <1> 首先嘗試從三級緩存中獲取實例

      • <2> 如果三級緩存都沒有獲取到bean實例,則說明需要創(chuàng)建該實例,則進行bean的實例化

      • <3> 將創(chuàng)建好的實例,放入一級緩存中

      2.1 從緩存中獲取Bean

      從三級緩存中讀取實例的代碼如下:

      // org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.java
      
      protected Object getSingleton(String beanName, boolean allowEarlyReference) {
      	// Quick check for existing instance without full singleton lock
      	// 從單例緩沖中加載 bean(一級緩存)
      	Object singletonObject = this.singletonObjects.get(beanName);
      	// 緩存中的 bean 為空,且當前 bean 正在創(chuàng)建
      	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      		// 二級緩存
      		singletonObject = this.earlySingletonObjects.get(beanName);
      		// 如果earlySingletonObjects 中沒有,且允許提前創(chuàng)建
      		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) {
      						// 從 singletonFactories 中獲取對應(yīng)的 ObjectFactory(三級緩存)
      						ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
      						if (singletonFactory != null) {
                                  //<1.1>
      							// 獲得 bean
      							singletonObject = singletonFactory.getObject();
      							// 添加 bean 到 早期單例對象的緩存 中
      							this.earlySingletonObjects.put(beanName, singletonObject);
      							// 從 singletonFactories 中移除對應(yīng)的 ObjectFactory
      							this.singletonFactories.remove(beanName);
      						}
      					}
      				}
      			}
      		}
      	}
      	return singletonObject;
      }
      

      <1.1>處,如果從三級緩存中獲取到實例后,就會放入二級緩存,并刪除三級緩存。

      2.2 實例化Bean

      <2>處,如果三級緩存都沒有獲取到bean實例,則說明需要創(chuàng)建該實例,則進行bean的實例化,代碼如下:

      //org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.java
      @Override
      protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      		throws BeanCreationException {
      	....
      	try {
      		// <2.1> 創(chuàng)建 Bean 對象
      		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      		if (logger.isTraceEnabled()) {
      			logger.trace("Finished creating instance of bean '" + beanName + "'");
      		}
      		return beanInstance;
      	}
      	....
      }
      

      調(diào)用doCreateBean方法創(chuàng)建實例:

      protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      		throws BeanCreationException {
      
      	...
      	// <2.1.1> 使用合適的實例化策略來創(chuàng)建新的實例:工廠方法、構(gòu)造函數(shù)自動注入、簡單初始化
      	if (instanceWrapper == null) {
      		instanceWrapper = createBeanInstance(beanName, mbd, args);
      	}
      	...
              
      	// <2.1.2> 判斷是否有后置處理
      	// 如果有后置處理,則允許后置處理修改 BeanDefinition
      	synchronized (mbd.postProcessingLock) {
      		if (!mbd.postProcessed) {
      			try {
      				// 后置處理修改 BeanDefinition
      				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
      			}
      			catch (Throwable ex) {
      				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
      						"Post-processing of merged bean definition failed", ex);
      			}
      			mbd.postProcessed = true;
      		}
      	}
      
      	// <2.1.3> 解決單例模式的循環(huán)依賴
      	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
      			isSingletonCurrentlyInCreation(beanName));
      	if (earlySingletonExposure) {
      		if (logger.isTraceEnabled()) {
      			logger.trace("Eagerly caching bean '" + beanName +
      					"' to allow for resolving potential circular references");
      		}
      		// 提前將創(chuàng)建的 bean 實例加入到 singletonFactories(三級緩存) 中 
      		// 這里是為了后期避免循環(huán)依賴
      		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
      	}
      
      	// 開始初始化 bean 實例對象
      	Object exposedObject = bean;
      	try {
      		// <2.1.4> 對 bean 進行填充,將各個屬性值注入,其中,可能存在依賴于其他 bean 的屬性
      		// 則會遞歸初始依賴 bean
      		populateBean(beanName, mbd, instanceWrapper);
      		// <2.1.5> 調(diào)用初始化方法
      		exposedObject = initializeBean(beanName, exposedObject, mbd);
      	}
      	...
      
      	return exposedObject;
      }
      

      該方法整體流程比較復(fù)雜,詳細邏輯可以參考 《創(chuàng)建Bean的流程》,但是整體流程如下:

      • <2.1.1> 使用合適的實例化策略來創(chuàng)建新的實例:工廠方法、構(gòu)造函數(shù)自動注入、簡單初始化
      • <2.1.2> 后置處理
      • <2.1.3> 判斷是否提前曝光,如果提前曝光,則將當前Bean的ObjectFactory放入三級緩存中。
      • <2.1.4> 對 bean 進行填充,其中,如果依賴于其他 bean 的屬性,則會遞歸調(diào)用getBean創(chuàng)建依賴的實例。
      • <2.1.5> 調(diào)用初始化方法

      解決循環(huán)依賴非常關(guān)鍵的一步就是<2.1.3>,將當前剛創(chuàng)建好的Bean實例(未初始化),封裝成ObjectFactory,放入三級緩存中:

      // org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
      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);
      		}
      	}
      }
      

      2.3 將創(chuàng)建好的Bean實例放入一級緩存

      <3>處,將創(chuàng)建好的實例,放入一級緩存中,代碼如下:

      	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
      		Assert.notNull(beanName, "Bean name must not be null");
      		// 全局鎖
      		synchronized (this.singletonObjects) {
      			...
      			try {
      				// <3.1> 初始化 bean
      				// 這個過程其實是調(diào)用 createBean() 方法(策略模式,具體的創(chuàng)建邏輯由傳入的ObjectFactory決定)
      				singletonObject = singletonFactory.getObject();
      				newSingleton = true;
      			}
      			...
      			// <3.2> 加入一級緩存中
      			if (newSingleton) {
      				addSingleton(beanName, singletonObject);
      			}
      			return singletonObject;
      		}
      	}
      
      • <3.1>,調(diào)用<2>處的代碼創(chuàng)建實例,詳見 《2.2 實例化Bean》
      • <3.2>,由于<2>處的代碼創(chuàng)建的實例已經(jīng)是初始化完成的,所以在此處將Bean實例加入一級緩存中。

      2.4 整體流程

      2.5 循環(huán)依賴流程

      我們以最簡單的循環(huán)依賴為例,A、B兩個類都互相依賴對方:

      public class A {
          private B b;
      }
      
      public class B {
          private A a;
      }
      

      假如Spring容器啟動時,先加載A,那么A、B循環(huán)依賴初始化流程如下圖所示:

      本文參考至:

      Spring為什么不使用二級緩存?Spring 動態(tài)代理時是如何解決循環(huán)依賴的?為什么要使用三級緩存?… - 知乎 (zhihu.com)

      Spring循環(huán)依賴三級緩存是否可以去掉第三級緩存? - SegmentFault 思否

      posted @ 2022-04-10 18:36  聽到微笑  閱讀(159)  評論(0)    收藏  舉報  來源
      主站蜘蛛池模板: 国产亚洲真人做受在线观看| 一区二区三区四区亚洲综合| 免费午夜无码片在线观看影院 | 成人免费AA片在线观看| AV教师一区高清| 深夜国产成人福利在线观看| 日本黄色三级一区二区三区| 国产成人免费午夜在线观看| 色欲综合久久中文字幕网| 福利视频在线播放| 国产蜜臀视频一区二区三区| 国产精品青青在线观看爽香蕉| a4yy私人毛片| 少妇被无套内谢免费看| 精品国产一区二区三区av片| 成人3d动漫一区二区三区| 91在线视频视频在线| 国产成人8X人网站视频| 精品国产粉嫩一区二区三区| 久久天天躁狠狠躁夜夜躁| 久久97超碰色中文字幕蜜芽| 99久久婷婷国产综合精品青草漫画 | 亚洲国产成人va在线观看天堂| 国产另类ts人妖一区二区| 88国产精品视频一区二区三区| 欧美人人妻人人澡人人尤物| 国产成人精品日本亚洲专区6| 毛片内射久久久一区| 亚洲高清激情一区二区三区 | 无码专区视频精品老司机| 国产成人精品亚洲一区二区| 四虎www永久在线精品| 国精偷拍一区二区三区| 久99久热只有精品国产99| AV无码免费不卡在线观看| 人妻丝袜AV中文系列先锋影音| 国产精品天天在线午夜更新| 国产一区二区三区美女| 亚洲天堂av 在线| 最新精品国偷自产在线美女足| 四虎国产精品永久在线下载|