精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

堂妹讓我聊:Spring循環(huán)依賴

開發(fā) 前端
作為面試者的他們來說就只能答出用三層緩存處理,而不清楚為什么是三層緩存。基于以上問題還是再跟學(xué)弟學(xué)妹們分析一下Spring中的循環(huán)依賴問題。

[[420916]]

在跟學(xué)弟學(xué)妹們聊完Spring IOC之后,有學(xué)弟反饋他們面試經(jīng)常會遇到面試官詢問Spring 里面的循環(huán)依賴問題。

而作為面試者的他們來說就只能答出用三層緩存處理,而不清楚為什么是三層緩存。基于以上問題還是再跟學(xué)弟學(xué)妹們分析一下Spring中的循環(huán)依賴問題。

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

  • 假設(shè)現(xiàn)在有一個對象A里面有一個屬性Class B,同樣的Class B對象中有一個Class A 的對象屬性,那么這兩個對象能相互創(chuàng)建成功嗎?

可能一般的普通代碼來說肯定是可以實現(xiàn):

  1. A a = new A() 
  2. B b = new B() 
  3. a.setB(b) 
  4. b.setA (a) 

看過之前講的IOC的同學(xué)應(yīng)該知道Spring官方是推薦使用構(gòu)造器注入的,所以如果是通過構(gòu)造器注入那就會產(chǎn)生一個無限循環(huán)注入的問題了,如下圖所示,永遠出來不?

  1. A a = new A( new B( new A(new B(......)))) 

所以面試過程中的循環(huán)依賴問題其實都是問Setter方式內(nèi)部如何解決循環(huán)依賴的?而不是問的構(gòu)造器。

比較初級的回答可能會說 是通過三層緩存,再好一點的回加上 三層緩存加上 提前暴露對象的方式(半成品)解決循環(huán)依賴問題

那什么是提前暴露對象呢?說白了就是spring IOC 容器的啟動過程 bean 的整個生命周期過程處理的邏輯。之前跟大家聊SpringIOC的過程已經(jīng)跟大家詳細分享過了,就不再啰嗦了,還不了解的可以再去復(fù)習(xí)一下。

這里就直接再畫一個流程圖,大家針對這個圖做一下回歸復(fù)習(xí):

上面的這張圖其實就是給大家說明了我們創(chuàng)建對象的時候可以分為兩個大步驟,一個實例化,一個初始化。

同樣的現(xiàn)在接著回到上面的問題,Setter是在哪一步處理緩存依賴的呢?

回顧整個流程我們大致可以按照這個思路來:

一個對象的創(chuàng)建 -> 實例化 -> 初始化(設(shè)置屬性值)

那構(gòu)造器的那種方式在流程中怎么體現(xiàn)出這個環(huán)呢?給大家畫了一個圖如下:

  • springIOC容器中的bean默認都是單例的,這個大家應(yīng)該清楚的。所以在設(shè)置屬性的時候可以直接在容器中獲取,按照上面的創(chuàng)建流程那整個循環(huán)依賴就產(chǎn)生了。
  • 三層緩存依賴,其實就是先把實例化的對象,放置在緩存中,等后續(xù)在根據(jù)A對象的引用完成賦值操作。

處理完的流程就是如下所示了:

在改進的圖中其實已經(jīng)可以發(fā)現(xiàn),環(huán) 已經(jīng)被打開了。整個可以如下幾步:

在實例化A對象之后就向容器中添加一個緩存,存放一個實例化但未初始化完成的對象(半成品對象)。

在第一次創(chuàng)建A對象中容器已經(jīng)有一個A對象,但是沒有B對象,所以在開始創(chuàng)建B對象時,在完成B對象的實例化之后,開始初始化屬性賦值時,此時容器中已經(jīng)有A對象,所以可以直接通過A的屬性賦值,同樣的B對象完成初始化之后也就可以再接著完成初始化A對象了,那整個A對象和B對象的創(chuàng)建過程就完成了。

廢話不多說了還是直接看下Spring中源碼來解析一下:

  1. * @author Juergen Hoeller 
  2. * @since 2.0 
  3. * @see #registerSingleton 
  4. * @see #registerDisposableBean 
  5. * @see org.springframework.beans.factory.DisposableBean 
  6. * @see org.springframework.beans.factory.config.ConfigurableBeanFactory 
  7. */ 
  8. ublic class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { 
  9.  
  10. /** Cache of singleton objects: bean name to bean instance. */ 
  11. private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); 
  12.  
  13. /** Cache of singleton factories: bean name to ObjectFactory. */ 
  14. private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); 
  15.  
  16. /** Cache of early singleton objects: bean name to bean instance. */ 
  17. private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); 
  18.   
  19.  // 省略其他的一些方法。。。 
  • 一級緩存:singletonObjects
  • 二級緩存:earlySingletonObjects
  • 三級緩存:singletonFactories,第三級緩存存放的是ObjectFactory-》FunctionalInterface 即函數(shù)式接口

那么Spring中是怎么使用這三級緩存去處理依賴呢?

為了搞明白這個過程只能是debug源碼了,因為整個過程比較長,沒辦法做成動圖的形式,所以只能給大家一步一步說明了。

之前跟大家講SpringIOC中的有個關(guān)鍵方法refresh(),這里面包含了13個核心的子方法,不了解的同學(xué)可以去復(fù)習(xí)一下前面講的SpringIOC啟動過程。

在13個子方法中有一個finishBeanFactoryInitialization(beanFactory) ;初始化剩下的單實例(非懶加載的)方法。這個就是開始入口了。

  1. public void refresh() throws BeansException, IllegalStateException { 
  2.    //   添加一個synchronized 防止出現(xiàn)refresh還沒有完成出現(xiàn)其他的操作(啟動,或者銷毀)  
  3.    synchronized (this.startupShutdownMonitor) { 
  4.       // 1.準備工作 
  5.       // 記錄下容器的啟動時間、 
  6.       // 標記“已啟動”狀態(tài),關(guān)閉狀態(tài)為false、 
  7.       // 加載當前系統(tǒng)屬性到環(huán)境對象中 
  8.       // 準備一系列監(jiān)聽器以及事件集合對象 
  9.        prepareRefresh(); 
  10.  
  11.       // 2. 創(chuàng)建容器對象:DefaultListableBeanFactory,加載XML配置文件的屬性到當前的工廠中(默認用命名空間來解析),就是上面說的BeanDefinition(bean的定義信息)這里還沒有初始化,只是配置信息都提取出來了,(包含里面的value值其實都只是占位符) 
  12.       ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 
  13.  
  14.       // 3. BeanFactory的準備工作,設(shè)置BeanFactory的類加載器,添加幾個BeanPostProcessor,手動注冊幾個特殊的bean等 
  15.       prepareBeanFactory(beanFactory); 
  16.       try { 
  17.          // 4.子類的覆蓋方法做額外的處理,就是我們剛開始說的 BeanFactoryPostProcessor ,具體的子類可以在這步的時候添加一些特殊的BeanFactoryPostProcessor完成對beanFactory修改或者擴展。 
  18.          // 到這里的時候,所有的Bean都加載、注冊完成了,但是都還沒有初始化 
  19.          postProcessBeanFactory(beanFactory); 
  20.          // 5.調(diào)用 BeanFactoryPostProcessor 各個實現(xiàn)類的 postProcessBeanFactory(factory) 方法 
  21.          invokeBeanFactoryPostProcessors(beanFactory); 
  22.  
  23.          // 6.注冊 BeanPostProcessor  處理器 這里只是注冊功能,真正的調(diào)用的是getBean方法 
  24.         registerBeanPostProcessors(beanFactory); 
  25.  
  26.          // 7.初始化當前 ApplicationContext 的 MessageSource,即國際化處理 
  27.          initMessageSource(); 
  28.  
  29.          // 8.初始化當前 ApplicationContext 的事件廣播器, 
  30.          initApplicationEventMulticaster(); 
  31.  
  32.          // 9.從方法名就可以知道,典型的模板方法(鉤子方法),感興趣的同學(xué)還可以再去復(fù)習(xí)一下之前寫的設(shè)計模式中的-模版方法模式 
  33.          //  具體的子類可以在這里初始化一些特殊的Bean(在初始化 singleton beans 之前) 
  34.          onRefresh(); 
  35.  
  36.          // 10.注冊事件監(jiān)聽器,監(jiān)聽器需要實現(xiàn) ApplicationListener 接口。這也不是我們的重點,過 
  37.          registerListeners(); 
  38.  
  39.          // 11.初始化所有的 singleton beans(lazy-init 的除外),重點關(guān)注 
  40.          finishBeanFactoryInitialization(beanFactory); 
  41.  
  42.          // 12.廣播事件,ApplicationContext 初始化完成 
  43.          finishRefresh(); 
  44.       } 
  45.       catch (BeansException ex) { 
  46.          if (logger.isWarnEnabled()) { 
  47.             logger.warn("Exception encountered during context initialization - " + 
  48.                   "cancelling refresh attempt: " + ex); 
  49.          } 
  50.          // 13.銷毀已經(jīng)初始化的 singleton 的 Beans,以免有些 bean 會一直占用資源 
  51.          destroyBeans(); 
  52.          cancelRefresh(ex); 
  53.          // 把異常往外拋 
  54.          throw ex; 
  55.       } 
  56.       finally { 
  57.          // Reset common introspection caches in Spring's core, since we 
  58.          // might not ever need metadata for singleton beans anymore... 
  59.          resetCommonCaches(); 
  60.       } 
  61.    } 

1.因為IOC作為Spring的容器,且默認的都是單例的,所以在我們創(chuàng)建bean之前都會去getBean一把,判斷當前是否有,當沒有時才會去創(chuàng)建。

所以進入finishBeanFactoryInitialization方法中找到 beanFactory.preInstantiateSingletons();

  1. protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { 
  2.  // 省略其他干擾代碼(判斷邏輯)。。。 
  3.    
  4.  
  5.  // Instantiate all remaining (non-lazy-init) singletons. 
  6.    // 實例化剩下的所有的單例對象(非懶加載的) 
  7.  beanFactory.preInstantiateSingletons(); 

進入到 preInstantiateSingletons 方法中,可以看到通過beanDefinitionNames(bean的定義信息)來判斷當前需要創(chuàng)建的bean信息,所以開始通過beanName循環(huán)開始走創(chuàng)建流程。

因為是我們創(chuàng)建的普通的bean實例,所以肯定會走到最下面的getBean(beanName);方法中,如下代碼所示:

  1. @Override 
  2. public void preInstantiateSingletons() throws BeansException { 
  3.  if (logger.isTraceEnabled()) { 
  4.   logger.trace("Pre-instantiating singletons in " + this); 
  5.  } 
  6.  
  7.  // Iterate over a copy to allow for init methods which in turn register new bean definitions. 
  8.  // While this may not be part of the regular factory bootstrap, it does otherwise work fine. 
  9.  List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); 
  10.  
  11.  // Trigger initialization of all non-lazy singleton beans... 
  12.  for (String beanName : beanNames) { 
  13.   RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); 
  14.   if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { 
  15.        // 判斷是否是工廠bean 
  16.    if (isFactoryBean(beanName)) { 
  17.     Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); 
  18.     if (bean instanceof FactoryBean) { 
  19.      final FactoryBean<?> factory = (FactoryBean<?>) bean; 
  20.      boolean isEagerInit; 
  21.      if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { 
  22.       isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) 
  23.           ((SmartFactoryBean<?>) factory)::isEagerInit, 
  24.         getAccessControlContext()); 
  25.      } 
  26.      else { 
  27.       isEagerInit = (factory instanceof SmartFactoryBean && 
  28.         ((SmartFactoryBean<?>) factory).isEagerInit()); 
  29.      } 
  30.      if (isEagerInit) { 
  31.       getBean(beanName); 
  32.      } 
  33.     } 
  34.    } 
  35.    else { 
  36.          // 如果當前beanName對應(yīng)的bean不是工廠bean,則通過beanName來獲取bean的實例 
  37.     getBean(beanName); 
  38.    } 
  39.   } 
  40.  } 
  41.  } 

進入到這個getBean(beanName);方法中有一個doGetBean方法,在Spring源碼中真正開始干活做事情的都一定會打上do的前綴方法。

  1. @Override 
  2. public Object getBean(String name) throws BeansException { 
  3.    // 實際獲取bean的方法,觸發(fā)依賴注入方法 
  4.  return doGetBean(namenullnullfalse); 

所以在進到doGetBean的方法中,還是會默認先去獲取一把,沒有則開始創(chuàng)建進入createBean(beanName, mbd, args)方法。

  1. protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, 
  2.   @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { 
  3.  
  4.  final String beanName = transformedBeanName(name); 
  5.  Object bean; 
  6.  
  7.  // Eagerly check singleton cache for manually registered singletons. 
  8.    // 確認一下容器中是否已經(jīng)有了當前bean實例 
  9.  Object sharedInstance = getSingleton(beanName); 
  10.  if (sharedInstance != null && args == null) { 
  11.   if (logger.isTraceEnabled()) { 
  12.    if (isSingletonCurrentlyInCreation(beanName)) { 
  13.     logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + 
  14.       "' that is not fully initialized yet - a consequence of a circular reference"); 
  15.    } 
  16.    else { 
  17.     logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); 
  18.    } 
  19.   } 
  20.   bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 
  21.  } 
  22.     
  23.  // 省略其他邏輯代碼。。。 
  24.  
  25.    // Create bean instance. 
  26.      // 創(chuàng)建Bean的實例對象 
  27.    if (mbd.isSingleton()) { 
  28.          // 返回以beanName的單例對象,如果沒有注冊,則使用singletonFactory創(chuàng)建并且注冊一個。 
  29.     sharedInstance = getSingleton(beanName, () -> { 
  30.      try { 
  31.              // 為給定的BeanDefinition(和參數(shù))創(chuàng)建一個Bean的實例 重點 
  32.       return createBean(beanName, mbd, args); 
  33.      } 
  34.      catch (BeansException ex) { 
  35.       // Explicitly remove instance from singleton cache: It might have been put there 
  36.       // eagerly by the creation process, to allow for circular reference resolution. 
  37.       // Also remove any beans that received a temporary reference to the bean. 
  38.       destroySingleton(beanName); 
  39.       throw ex; 
  40.      } 
  41.     }); 
  42.     bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 
  43.    } 
  44.         
  45.   // 省略其他邏輯代碼。。。 
  46.  return (T) bean; 

在上面沒有獲取到bean時候則開始創(chuàng)建bean了,所以直接進到createBean的方法中,因為是容器初始化啟動所以肯定是沒有的,顧一定會進入createBean的方法中,所以再進入createBean的方法中。

  1. @Override 
  2.  protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 
  3.    throws BeanCreationException { 
  4.   // 省略其他相關(guān)代碼。。。。。 
  5.  
  6.   try { 
  7.       // 實際創(chuàng)建Bean的調(diào)用 重點 
  8.    Object beanInstance = doCreateBean(beanName, mbdToUse, args); 
  9.    if (logger.isTraceEnabled()) { 
  10.     logger.trace("Finished creating instance of bean '" + beanName + "'"); 
  11.    } 
  12.    return beanInstance; 
  13.   } 
  14.   catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { 
  15.    // A previously detected exception with proper bean creation context already, 
  16.    // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. 
  17.    throw ex; 
  18.   } 
  19.   catch (Throwable ex) { 
  20.    throw new BeanCreationException( 
  21.      mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); 
  22.   } 
  23.  } 

看到doCreateBean方法那說明要開始真正的創(chuàng)建Bean了。

  1. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) 
  2.   throws BeanCreationException { 
  3.  
  4.  // Instantiate the bean. 
  5.  BeanWrapper instanceWrapper = null
  6.  if (mbd.isSingleton()) { 
  7.      // 判斷如果是單例對象,則從factoryBean實例緩存匯總移除當前Bean的定義信息 
  8.   instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); 
  9.  } 
  10.  if (instanceWrapper == null) { 
  11.      // 根據(jù)執(zhí)行的bean使用的對應(yīng)的策略創(chuàng)建新的實例。也可以理解實例化對象,在內(nèi)存總開辟空間 
  12.   instanceWrapper = createBeanInstance(beanName, mbd, args); 
  13.  } 
  14.  final Object bean = instanceWrapper.getWrappedInstance(); 
  15.  Class<?> beanType = instanceWrapper.getWrappedClass(); 
  16.  if (beanType != NullBean.class) { 
  17.   mbd.resolvedTargetType = beanType; 
  18.  } 
  19.  
  20.  // 省略其他的相關(guān)代碼。。。。。 
  21.     
  22.    // Eagerly cache singletons to be able to resolve circular references 
  23.  // even when triggered by lifecycle interfaces like BeanFactoryAware. 
  24.    // 判斷當前bean是否需要提前曝光,單例&允許循環(huán)依賴&當前bean正在創(chuàng)建,檢測循環(huán)依賴 
  25.     boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && 
  26.    isSingletonCurrentlyInCreation(beanName)); 
  27.  if (earlySingletonExposure) { 
  28.   if (logger.isTraceEnabled()) { 
  29.    logger.trace("Eagerly caching bean '" + beanName + 
  30.      "' to allow for resolving potential circular references"); 
  31.   } 
  32.      // 在bean的初始化完成之前將創(chuàng)建的實例加入ObjectFactory(添加三級緩存),主要是為了防止后期的循環(huán)依賴。。。。重點 
  33.   addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 
  34.  } 
  35.     
  36.    Object exposedObject = bean; 
  37.  try { 
  38.      // 填充bean屬性,假設(shè)其中存在依賴于其他的bean的屬性,則會遞歸初始化依賴的bean 
  39.   populateBean(beanName, mbd, instanceWrapper); 
  40.      //執(zhí)行初始化邏輯 
  41.   exposedObject = initializeBean(beanName, exposedObject, mbd); 
  42.  } 
  43.  catch (Throwable ex) { 
  44.   if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { 
  45.    throw (BeanCreationException) ex; 
  46.   } 
  47.   else { 
  48.    throw new BeanCreationException( 
  49.      mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); 
  50.   } 
  51.  } 
  52.     
  53.  return exposedObject; 

進入到doCreateBean中首先需要核心看的一個方法createBeanInstance,這個方法就是真正的創(chuàng)建bean實例例,也就是在內(nèi)存中開辟空間(實例化),完事之后就開始看第二個重點添加緩存。

  • addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  • 這個方法點進去,其實就是能發(fā)現(xiàn)開始添加到第三級緩存中,value值就是一個函數(shù)方法getEarlyBeanReference,不熟悉的同學(xué)可以看下JDK1.8的新特性。同時也標注了當前bean正在注冊中。

實例化完bean按照bean的生命周期流程那肯定就是開始初始化bean了,填充屬性,接著向下看有一個populateBean(填充bean屬性)。

  1. populateBean(beanName, mbd, instanceWrapper); 

在populateBean這個過程中就有很大的邏輯在里面了,比如說獲取屬性名稱,屬性值等等一系列操作。但是核心的還是需要看applyPropertyValues方法屬性賦值,如下所示:

  1. protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { 
  2.   // 省略一堆其他判斷校驗邏輯代碼,直接看到最后。。。 
  3.   if (pvs != null) { 
  4.       // 應(yīng)用給定的屬性值,解決任何在這個bean工廠運行時其他的bean的調(diào)用(就是設(shè)置屬性值) 
  5.    applyPropertyValues(beanName, mbd, bw, pvs); 
  6.   } 
  7.  } 

同樣的進入applyPropertyValues方法。

  1. protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { 
  2.   // 省略其他的一些校驗代碼。。。。。 
  3.  
  4.  // Create a deep copy, resolving any references for values
  5.  List<PropertyValue> deepCopy = new ArrayList<>(original.size()); 
  6.  boolean resolveNecessary = false
  7.    // 便利屬性,將屬性轉(zhuǎn)換為對應(yīng)類的對應(yīng)屬性類型 
  8.  for (PropertyValue pv : original) { 
  9.      // 判斷當前屬性是否已經(jīng)解析過 
  10.   if (pv.isConverted()) { 
  11.    deepCopy.add(pv); 
  12.   } 
  13.   else { 
  14.        // 獲取屬性明層 
  15.    String propertyName = pv.getName(); 
  16.        // 獲取屬性值 
  17.    Object originalValue = pv.getValue(); 
  18.        // valueResolver處理pv解析出的originalValue封裝的對象(是否必要開始去處理屬性值了)重點 
  19.    Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); 
  20.    // 默認轉(zhuǎn)換后的值等于解析出來的值    
  21.        Object convertedValue = resolvedValue; 
  22.        // 判斷轉(zhuǎn)換標記  
  23.    boolean convertible = bw.isWritableProperty(propertyName) && 
  24.      !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); 
  25.    if (convertible) { 
  26.     convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter); 
  27.    } 
  28.    // 省略其他的代碼邏輯。。。。 

applyPropertyValues方法中需要注意的是valueResolver.resolveValueIfNecessary值處理器。

  • Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);

這一步主要是判斷屬性值是否需要處理,因為之前這個value值是存方法接口方法

所以在執(zhí)行valueResolver.resolveValueIfNecessary方法時,一定會去處理,那再看看里面又處理什么邏輯?

  1. public Object resolveValueIfNecessary(Object argName, @Nullable Object value) { 
  2.   // We must check each value to see whether it requires a runtime reference 
  3.   // to another bean to be resolved. 
  4.   // 如果value是RuntimeBeanReference實例 則處理 
  5.   if (value instanceof RuntimeBeanReference) { 
  6.    RuntimeBeanReference ref = (RuntimeBeanReference) value; 
  7.       // 解析出對應(yīng)的ref 所封裝的Bean元信息(Bean的名稱,Bean的類型) 的對象 
  8.    return resolveReference(argName, ref); 
  9.   } 
  10.      // 省略其他的邏輯代碼 
  11.   } 

面的斷點的截圖已經(jīng)可以明確的看到value值是RuntimeBeanReference實例,所以接下來就一定會去調(diào)用resolveReference方法解析ref所封裝的bean信息,那就再接著進入resolveReference方法看看干了什么?

  1. @Nullable 
  2. private Object resolveReference(Object argName, RuntimeBeanReference ref) { 
  3.  try { 
  4.   Object bean; 
  5.   String refName = ref.getBeanName(); 
  6.   refName = String.valueOf(doEvaluate(refName)); 
  7.   if (ref.isToParent()) { 
  8.    if (this.beanFactory.getParentBeanFactory() == null) { 
  9.     throw new BeanCreationException( 
  10.       this.beanDefinition.getResourceDescription(), this.beanName, 
  11.       "Can't resolve reference to bean '" + refName + 
  12.       "' in parent factory: no parent factory available"); 
  13.    } 
  14.    bean = this.beanFactory.getParentBeanFactory().getBean(refName); 
  15.   } 
  16.   else { 
  17.        // 獲取resolvedName的Bean對象 重點 
  18.    bean = this.beanFactory.getBean(refName); 
  19.        // 注冊beanName到dependentBeanName的依賴關(guān)系到Bean的工中 
  20.    this.beanFactory.registerDependentBean(refName, this.beanName); 
  21.   } 
  22.   if (bean instanceof NullBean) { 
  23.    bean = null
  24.   } 
  25.      // 返回解析出來的對用的ref所封裝的Bean對象 
  26.   return bean; 
  27.  } 
  28.  catch (BeansException ex) { 
  29.   throw new BeanCreationException( 
  30.     this.beanDefinition.getResourceDescription(), this.beanName, 
  31.     "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex); 
  32.  } 

上面已經(jīng)進入到resolveReference來處理ref中所以引用的Bean對象,又因為SpringIOC默認都是單例Bean,所以肯定還是在beanFactory中去獲取Bean。

  • bean = this.beanFactory.getBean(refName);

至此又開始循環(huán)創(chuàng)建循環(huán)依賴的對象,假設(shè)還是一開始的A和B兩個對象來說,那么開始是創(chuàng)建A對象時,在設(shè)置B屬性的時候,沒有B屬性,那么現(xiàn)在剛好就是開始創(chuàng)建B屬性了。同樣的B對象又開始填充屬性A。

細心的同學(xué)應(yīng)發(fā)現(xiàn)問題了,這不就是無限循環(huán)了嗎?還怎么處理循環(huán)啊?這不是扯淡嗎?

其實不是的,其實創(chuàng)建B對象想的時候,去獲取A的Bean信息時,因為A還是在創(chuàng)建中,所以在接下來中從新走流程中會有一個新的發(fā)現(xiàn),進入緩存中獲取對象,如下:

  1. bean = this.beanFactory.getBean(refName) ->  doGetBean(namenullnullfalse) -> sharedInstance = getSingleton(beanName) -> getSingleton(beanName, true)  
  2.    // 具體點 getSingleton 方法的內(nèi)部實現(xiàn) 
  3.    // 進入getSingleton方法中 isSingletonCurrentlyInCreation 當前的Bean正在創(chuàng)建中 
  4.    protected Object getSingleton(String beanName, boolean allowEarlyReference) { 
  5.    // 從一級緩存獲取BeanName對應(yīng)的單例對象 
  6.   Object singletonObject = this.singletonObjects.get(beanName); 
  7.    // 如果沒有獲取到,但是當前 BeanName對應(yīng)的單例對象又處于創(chuàng)建中 
  8.   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { 
  9.    synchronized (this.singletonObjects) { 
  10.         // 從二級緩存中獲取當前BeanName對應(yīng)的單例對象 
  11.     singletonObject = this.earlySingletonObjects.get(beanName); 
  12.         // 二級緩存中沒有,但是allowEarlyReference為true,在doCreateBean方法中已經(jīng)設(shè)置,所以這里為true 
  13.     if (singletonObject == null && allowEarlyReference) { 
  14.           // 從三級緩存中獲取 
  15.      ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); 
  16.      if (singletonFactory != null) { 
  17.             // 這里就是三級緩存函數(shù)方法,同過Factory創(chuàng)建一個單例對象 
  18.       singletonObject = singletonFactory.getObject(); 
  19.             // 添加到二級緩存中,半成品對象 
  20.       this.earlySingletonObjects.put(beanName, singletonObject); 
  21.             // 同時刪除三級緩存 
  22.       this.singletonFactories.remove(beanName); 
  23.      } 
  24.     } 
  25.    } 
  26.   } 
  27.    // 返回當前半成品對象 
  28.   return singletonObject; 
  29.  } 

現(xiàn)在整個流程中二級緩存已經(jīng)存放了一個半成品A的對象,因此在創(chuàng)建B對象時,獲取A屬性填充值從容器緩存中已經(jīng)可以獲取到A對象的單例Bean,對B對象來說其實就是一個完整的單例Bean實例,因此再次getSingleton Bean時候會有一個判斷,如果有一個新的完成的單例Bean則會添加到一級緩存中,源碼如下:

  1. public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { 
  2.  Assert.notNull(beanName, "Bean name must not be null"); 
  3.  synchronized (this.singletonObjects) { 
  4.   Object singletonObject = this.singletonObjects.get(beanName); 
  5.   if (singletonObject == null) { 
  6.    if (this.singletonsCurrentlyInDestruction) { 
  7.     throw new BeanCreationNotAllowedException(beanName, 
  8.       "Singleton bean creation not allowed while singletons of this factory are in destruction " + 
  9.       "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); 
  10.    } 
  11.    if (logger.isDebugEnabled()) { 
  12.     logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); 
  13.    } 
  14.    beforeSingletonCreation(beanName); 
  15.    boolean newSingleton = false
  16.    boolean recordSuppressedExceptions = (this.suppressedExceptions == null); 
  17.    if (recordSuppressedExceptions) { 
  18.     this.suppressedExceptions = new LinkedHashSet<>(); 
  19.    } 
  20.    try { 
  21.     singletonObject = singletonFactory.getObject(); 
  22.     newSingleton = true
  23.    } 
  24.        // 省略其他的代碼邏輯 
  25.         
  26.    //判斷生成了新的單例對象 
  27.    if (newSingleton) { 
  28.          // 將添加BeanName和 singletonObject 添加到一級緩存中去 
  29.     addSingleton(beanName, singletonObject); 
  30.    } 
  31.   } 
  32.   return singletonObject; 
  33.  } 

上面聊到當新的單例對象生成會再調(diào)用addSingleton方法。

  1. protected void addSingleton(String beanName, Object singletonObject) { 
  2.  synchronized (this.singletonObjects) { 
  3.      // 添加到一級緩存中 
  4.   this.singletonObjects.put(beanName, singletonObject); 
  5.      // 移除二級緩存中的內(nèi)容 
  6.   this.singletonFactories.remove(beanName); 
  7.      // 移除三級緩存中的內(nèi)容 
  8.   this.earlySingletonObjects.remove(beanName); 
  9.      // 將完成的BeanName添加到已經(jīng)注冊的單例集合中 
  10.   this.registeredSingletons.add(beanName); 
  11.  } 

自此整個Spring的循環(huán)依賴過程就已經(jīng)結(jié)束了。

還是用開始的A,B兩個對象來總結(jié)一個流程吧

  • 當開始創(chuàng)建A對象時,實例化后,添加一步三級緩存,針對屬性賦值,因為此時還沒有B對象的實例,所以在獲取到A對象的B屬性的值的ref引用對象B,觸發(fā)創(chuàng)建B對象的創(chuàng)建,因此在B對象實例化后,在屬性賦值時,獲取到A屬性的ref引用對象,而因為之前A對象已經(jīng)完成實例化,并且添加到了三級緩存中,所以在B屬性創(chuàng)建設(shè)置A屬性時,因為此時A屬性正在被創(chuàng)建,所以可以從第三級緩存中獲取到值,同時把獲取到的值添加到二級緩存中,同時刪除第三級緩存的A對象。
  • 在創(chuàng)建B對象中已經(jīng)能獲取到A屬性值(半成品),所以B對象可以完成賦值狀態(tài),變成一個完整的B對象的實例。所以當新的單例對象生成會再調(diào)用addSingleton方法添加到一級緩存中,同時刪除 二級 三級緩存的值,所以回過頭來接著 A對象獲取B屬性值的時候已經(jīng)能在一級緩存中獲取到。所以也就可以完成屬性賦值,自此循環(huán)依賴完全打開。

循環(huán)依賴問題已經(jīng)跟大家聊完了,在看源碼的過程中大家一定要注意以下的6個方法:

這六個方法是核心處理流程,按照這個流程,以及我上面執(zhí)行的步驟一步一步斷點多走幾遍就能加深自己的理解了。

不要問我為啥知道這么多都是熬夜學(xué)習(xí)找資料肝出來的!!!

總結(jié)

還是之前的老步驟聊完之后跟大家介紹幾個比較常見的面試題來加深一個理解,也方便學(xué)弟學(xué)妹們面試。

一級二級 三級緩存中分別存放的是什么狀態(tài)的對象?

完整的看完這個文章的同學(xué)應(yīng)該是沒啥問題吧

  • 一級:完整的成品的對象
  • 二級:非完整的半成品對象
  • 三級:lambada表達式

假設(shè)只設(shè)計二級緩存能否解決循環(huán)依賴?

  • 只用二級緩存是可以解決緩存依賴的,(廢棄第三級,保留第一第二)但是會有一個問題,在配置AOP切面的時候會出錯,因為無法生成代理對象。
  • 所以三級緩存是為了處理AOP中的循環(huán)依賴。因為當配置了切面之后,在getEarlyBeanReference方法中,有可能會把之前的原始對象替換成代理對象,導(dǎo)致Bean的版本不是最終的版本,所以報錯。

我是敖丙,你知道的越多,你不知道的越多,下期見。

 

責(zé)任編輯:姜華 來源: 三太子敖丙
相關(guān)推薦

2020-03-12 15:00:44

JavaSpring依賴

2020-12-29 08:34:08

spring循環(huán)依賴開發(fā)

2023-05-04 08:06:27

Spring循環(huán)依賴

2025-03-17 00:21:00

2021-05-06 07:58:57

Spring BeanIOCAOP

2024-06-05 11:43:10

2020-05-07 10:05:58

Spring循環(huán)依賴Java

2023-10-07 08:40:57

緩存屬性Spring

2019-09-09 06:30:06

Springboot程序員開發(fā)

2021-06-25 09:47:59

Spring循環(huán)依賴Java

2020-07-29 10:40:21

Spring循環(huán)依賴Java

2020-02-10 15:50:18

Spring循環(huán)依賴Java

2021-10-21 08:31:31

Spring循環(huán)依賴面試

2019-11-26 14:30:20

Spring循環(huán)依賴Java

2024-08-27 11:00:56

單例池緩存bean

2024-04-03 09:03:05

2021-08-26 09:31:40

Nacos配置注冊

2024-04-15 08:17:21

Spring依賴注入循環(huán)依賴

2024-03-18 00:00:00

SpringBean設(shè)計

2022-08-17 07:52:31

Spring循環(huán)依賴單例池
點贊
收藏

51CTO技術(shù)棧公眾號

性久久久久久久久久| 国产资源在线免费观看| 中日精品一色哟哟| 国产探花在线精品一区二区| 91久久精品一区二区二区| 日韩视频在线观看国产| 国产绿帽刺激高潮对白| 激情自拍一区| 在线成人中文字幕| 香蕉久久久久久av成人| 欧美xxx视频| 亚洲精选免费视频| 日韩免费电影一区二区| 不卡的日韩av| 日本一不卡视频| 国内精品久久久久久久| 污污视频网站在线免费观看| silk一区二区三区精品视频| 欧美特级限制片免费在线观看| 国产在线视频在线| 国产高清一区在线观看| 成人晚上爱看视频| 国产综合香蕉五月婷在线| 国产小视频在线免费观看| 91久久国产| 日韩电影大片中文字幕| 女教师高潮黄又色视频| 91p九色成人| 欧美日韩国产精品一区二区三区四区 | 国产一级视频在线观看| 日韩中文欧美| 亚洲视频视频在线| 色噜噜在线观看| 99久久婷婷国产综合精品青牛牛| 欧美三级韩国三级日本三斤| 欧美s码亚洲码精品m码| eeuss鲁一区二区三区| 最新高清无码专区| 一区二区三区四区五区精品 | 久久一留热品黄| 成人综合色站| 精品久久久中文字幕人妻| 久久国产剧场电影| 国产精品久久久久福利| 99久在线精品99re8热| 国产精品二区影院| 美日韩精品免费视频| 很污很黄的网站| 日韩啪啪电影网| 在线国产精品播放| 日本综合在线观看| 欧美一区三区| 国产一区二区三区免费视频| 国产精品无码午夜福利| 色狠狠久久av综合| 亚洲码在线观看| 日韩精品电影一区二区| www.av天天| 黑人巨大亚洲一区二区久 | 第九区2中文字幕| 国产原创视频在线观看| 亚洲品质自拍视频网站| 中文字幕欧美日韩一区二区| 欧美极品视频| 亚洲欧美日本在线| 色撸撸在线观看| 正在播放一区| 精品不卡一区二区| 国产精品久久久亚洲一区| 性欧美xxxx视频在线观看| 日韩伦人妻无码| 亚洲激情av| 欧美一级电影在线| 中文字幕av网站| 蜜桃视频在线一区| 午夜精品影院在线观看| 国产精品亚洲欧美导航| 97精品久久人人爽人人爽| 精品无人码麻豆乱码1区2区| 99精彩视频| 欧美一级淫片aaaaaa| 99久久伊人精品| 欧美日韩在线精品| 欧美成人二区| 亚洲永久精品大片| 18岁网站在线观看| 日韩av电影资源网| 日韩一区二区免费在线电影| 中国免费黄色片| 国产精品欧美在线观看| 俺去亚洲欧洲欧美日韩| 国产这里有精品| 亚洲精选成人| 国产精品午夜视频| 狠狠躁日日躁夜夜躁av| 久久久久久毛片| 四虎免费在线观看视频| 黄色视屏在线免费观看| 欧美亚洲一区二区在线| 欧美熟妇精品一区二区| 九九在线精品| 欧美丰满老妇厨房牲生活| 日韩不卡视频在线| 麻豆国产精品一区二区三区 | 国产精品一区二区三区美女| 亚洲情综合五月天| 免费又黄又爽又色的视频| 久久精品一本| 成人av资源网| 在线观看完整版免费| 午夜精品影院在线观看| 午夜大片在线观看| 欧美猛男男男激情videos| 草民午夜欧美限制a级福利片| 国产精品久久久免费视频| 黄网站免费久久| 欧美一区亚洲二区| 96av在线| 欧美一级片在线| 国产午夜精品福利视频| 亚洲精选国产| 99国产在线视频| 在线国产91| 在线一区二区三区四区五区 | 国产农村妇女毛片精品久久麻豆| 日韩精品福利片午夜免费观看| 日本免费久久| 亚洲国产精品久久久久久| 精品人伦一区二区| 亚洲一区观看| 国产综合动作在线观看| 色女人在线视频| 欧美一区二区在线视频| 91麻豆制片厂| 日韩1区2区日韩1区2区| 久久精品日产第一区二区三区精品版| 在线看福利影| 欧美一区二区三区四区久久 | 香蕉久久一区二区不卡无毒影院| 午夜免费一级片| 欧美成人直播| 国产日韩欧美视频| 免费在线观看av网站| 91高清视频免费看| av黄色在线免费观看| 亚洲一级电影| 国产精品日韩欧美一区二区三区| 99热国产在线| 精品少妇一区二区三区免费观看 | 欧美激情综合色综合啪啪| 国产日韩欧美黄色| 国产丝袜在线| 日韩午夜在线播放| 992在线观看| 另类小说视频一区二区| 一本色道久久99精品综合| 天然素人一区二区视频| 尤物99国产成人精品视频| 日本视频免费观看| 久久久久久久久久电影| 国产精品亚洲a| 欧美日韩伦理| 91久久精品美女高潮| 午夜羞羞小视频在线观看| 日韩区在线观看| 国产精品111| 91欧美激情一区二区三区成人| 日韩免费一级视频| 精品久久精品| 91亚洲精华国产精华| 新版中文在线官网| 日韩高清免费观看| www.五月婷婷.com| 亚洲婷婷国产精品电影人久久| 午夜天堂在线视频| 亚洲区第一页| 日韩一区国产在线观看| 国产精久久久| 97人人模人人爽人人喊中文字 | www一区二区www免费| 蜜臀av免费一区二区三区| 国产精品久久久久久av| 1024在线播放| 日韩精品中文字| 亚洲天堂手机版| 亚洲国产成人精品视频| 性猛交娇小69hd| 国产一区二区网址| 免费黄色日本网站| 国产精品不卡| 久久国产精品一区二区三区四区| 在线日本欧美| 欧美极品美女视频网站在线观看免费| 欧美zozo| 日韩精品中文字幕在线不卡尤物 | 成人激情五月天| 国产一区二区三区免费观看| 免费av观看网址| 999国产精品永久免费视频app| 国产69精品久久久久9999apgf| 欧美xx视频| 久久久久久久久久久免费 | 欧美激情精品久久久久久久变态 | 国产视频一区二区三区在线观看| 中文字幕日韩综合| 亚洲女人av| 熟女视频一区二区三区| 啪啪亚洲精品| 不卡一卡2卡3卡4卡精品在| 视频二区不卡| 久久久免费精品| 米奇精品一区二区三区| 日韩国产中文字幕| 国产色视频在线| 欧美三电影在线| 日韩精品久久久久久久酒店| 日韩美女视频一区二区| 国产真实乱人偷精品人妻| 成人性生交大片免费看视频在线| 乌克兰美女av| 视频一区在线播放| 青草青青在线视频| 午夜久久美女| 一级一片免费播放| 国产一区不卡| 老牛影视免费一区二区| 亚洲精品一二三**| 96国产粉嫩美女| 国产91精品在线| 青青草原一区二区| 国产高潮在线| 国语自产精品视频在线看抢先版图片| 国产二区三区在线| 日韩中文字幕在线视频播放| 国产69精品久久app免费版| 日韩激情在线视频| 天天综合天天综合| 亚洲第一福利在线观看| 亚洲国产视频一区二区三区| 91精品国产欧美日韩| 91麻豆视频在线观看| 精品视频一区三区九区| 91麻豆精品在线| 欧美性高清videossexo| 无码人妻久久一区二区三区| 福利二区91精品bt7086| 欧美精品久久久久性色| 亚洲午夜一区二区| 久青草免费视频| 亚洲午夜羞羞片| 欧美亚洲天堂网| 亚洲一区电影777| 国产一级一片免费播放放a| 一区二区高清在线| 国产对白videos麻豆高潮| 亚洲一级片在线观看| 精品无码久久久久久久久| 亚洲一区电影777| 日本一区二区三区免费视频| 黄网动漫久久久| 久久久国产精品成人免费| 色婷婷国产精品| 男人天堂视频在线| 欧美日韩国产三级| 国产精品无码久久久久成人app| 欧美一区二区三区在| 亚洲国产精品久久久久爰性色| 精品88久久久久88久久久| 午夜黄色小视频| 国产一区二区三区在线免费观看| 幼a在线观看| 色综合视频一区中文字幕| 波多野结衣中文在线| 日韩免费在线播放| 欧美xxxx性| 成人片在线免费看| 亚洲自拍都市欧美小说| 亚洲人久久久| 欧美午夜一区| 已婚少妇美妙人妻系列| 狠狠色狠狠色综合系列| 无码人妻精品一区二区三区99不卡| av在线不卡观看免费观看| 色无极影院亚洲| 亚洲免费在线看| 国产高潮久久久| 6080午夜不卡| 天天操天天射天天舔| 中文字幕亚洲无线码a| 日韩经典av| 国产精品久久中文| 99精品中文字幕在线不卡 | 午夜久久99| 97公开免费视频| 国产**成人网毛片九色| 波多野结衣 在线| 亚洲乱码国产乱码精品精可以看| 伊人久久综合视频| 欧美高清你懂得| 亚洲欧美丝袜中文综合| 精品国产美女在线| 亚洲天堂免费电影| 91视频国产精品| 久久最新网址| 免费看黄在线看| 免费精品视频在线| 亚洲一区二区三区无码久久| 中文字幕一区二区三中文字幕| 日本中文字幕在线免费观看| 欧美精选午夜久久久乱码6080| 手机看片一区二区| 日韩小视频在线| 日韩av福利| 国产在线精品一区二区三区| 国产精品黑丝在线播放| 日韩欧美精品在线观看视频| 国产福利一区在线| 一本色道久久88| 色妹子一区二区| 亚洲日本香蕉视频| 欧美日韩国产成人| 日本中文字幕视频一区| 快播亚洲色图| 中文国产一区| 久久无码专区国产精品s| 中文字幕亚洲一区二区av在线| 亚洲 欧美 成人| 日韩成人黄色av| h片在线观看视频免费| 99r国产精品视频| 亚洲视频在线免费| 999在线观看| 国产精品丝袜91| 中文字幕精品一区二| 亚洲欧美在线免费| 国产污视频在线播放| 国产精品久久精品视| 中文字幕一区二区av| 最新av免费在线观看| 欧美激情一区二区三区全黄| 91在线视频免费播放| 国产视频一区在线| 亚洲欧美小说色综合小说一区| 久久99欧美| 亚洲日本久久| 蜜臀av一区二区三区有限公司| 亚洲国产综合在线| 蜜桃视频污在线观看| 国内精品伊人久久| 免费观看成人www动漫视频| 日本在线xxx| 91麻豆国产精品久久| 国产精品免费精品一区| 亚洲人成免费电影| 粉嫩91精品久久久久久久99蜜桃| 四虎一区二区| 精品一区二区三区在线视频| 国精产品一区一区二区三区mba| 88在线观看91蜜桃国自产| 成人国产免费电影| 97视频资源在线观看| 欧美午夜不卡影院在线观看完整版免费| 三大队在线观看| 无吗不卡中文字幕| 男女视频在线观看免费| 国产精品免费在线免费| 欧美丰满日韩| 可以看的av网址| 亚洲成av人片在线观看无码| 巨骚激情综合| 国产日韩欧美黄色| 激情欧美一区| 国产aⅴ激情无码久久久无码| 欧美日韩在线电影| 影音先锋中文在线视频| 黑人另类av| 日本一区中文字幕| 清纯粉嫩极品夜夜嗨av| 亚洲欧美日韩精品久久奇米色影视 | ...xxx性欧美| 风流少妇一区二区三区91| 国产999精品| 一本一本久久a久久综合精品| 亚洲香蕉中文网| 欧美无砖专区一中文字| 欧美人动性xxxxz0oz| 久久亚洲国产精品日日av夜夜| 男人的天堂久久精品| 精品午夜福利视频| 国产午夜精品美女视频明星a级| va天堂va亚洲va影视| 欧美黑人经典片免费观看| 中文字幕不卡三区| 男人天堂网在线视频| 国产精品香蕉在线观看| 1000部精品久久久久久久久| 丁香激情五月少妇| 亚洲精品一区二区精华| 影音成人av| 日本在线xxx|