日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
關(guān)于Spring中GetBean的全流程源碼解析

本文轉(zhuǎn)載自微信公眾號(hào)「bugstack蟲洞?!?,作者小傅哥 。轉(zhuǎn)載本文請(qǐng)聯(lián)系bugstack蟲洞棧公眾號(hào)。

一、前言

你提出問題,就要給出解決方案!

最近有粉絲小伙伴反饋,與自己的上級(jí)溝通總是遇到障礙,感覺不被理解。大部分時(shí)候他提出來的事情都可能會(huì)被領(lǐng)導(dǎo)說:“我沒get到你的點(diǎn)”、“你想做的這個(gè)項(xiàng)目沒有業(yè)務(wù)價(jià)值”、“你提出問題,就要給出解決方案”,等等諸如此類的回答。

鑒于具體情況要具體分析,可能我們并不一定能判斷出是誰(shuí)的問題,導(dǎo)致在每次的交談中出現(xiàn)的分歧??赡苁莑eader有l(wèi)eader的苦衷和視角,也可能是員工有員工的理解和想法,所以最終沒有達(dá)成一致。

但就帶團(tuán)隊(duì)來講,有效溝通很重要。就像:如果你說的都對(duì),那我為什么和你爭(zhēng)吵呢?與其壓制遇到的矛盾點(diǎn),不如都攤開了聊,誰(shuí)的視角和心胸更大,誰(shuí)就多有一些同理心。

如果尖銳的批評(píng)完全消失,溫和的批評(píng)將會(huì)變得刺耳。

如果溫和的批評(píng)也不被允許,沉默將被認(rèn)為居心叵測(cè)。

如果沉默也不再允許,贊揚(yáng)不夠賣力將是一種罪行。

如果只允許一種聲音存在,那么,唯一存在的那個(gè)聲音就是謊言。

二、面試題

謝飛機(jī),小記!,總感覺 Spring 也沒啥看的,怎么面試官一問就能問出花?

面試官:Spring 的 getBean 中,transformedBeanName 的作用是什么?

謝飛機(jī):不知道呀,看單詞意思好像是改變Bean名稱。

面試官:那這么說,你的 Bean 如果有 alias 別名,Spring 在獲取 Bean 時(shí)候要怎么處理?

謝飛機(jī):這!

面試官:那如果用了 depends-on 呢?

謝飛機(jī):啊, 我沒用過 depends-on 我不知道!

面試官:那你調(diào)試代碼時(shí)候,看見過BeanName前面有 & 的情況嗎,為啥會(huì)出現(xiàn)?

謝飛機(jī):我不配知道!再見!

三、Bean 的獲取過程

對(duì)于剛接觸看 Spring 源碼的伙伴來說,可能很疑惑于怎么就獲取一個(gè) Bean 就這么多流程呢?

  • 可能有 Bean 可能有別名、可能有依賴、也可能是被 BeanFactory 包裝過,所以會(huì)有 transformedBeanName 來處理這些差異化行為。
  • 有沒有循環(huán)依賴、有沒有父工廠、是單例還是原型、是懶加載還是預(yù)加載、在不在緩沖區(qū),所以就有各種組合判斷來做不同的流程。
  • 提早暴漏對(duì)象、三級(jí)緩存、后置標(biāo)記清楚,所有的優(yōu)化處理都是為了讓整個(gè) Bean 的獲取更加高效。

所以,它為了適應(yīng)各類的需求,變得越來越復(fù)雜了。而這部分知識(shí)的深入學(xué)習(xí)絕對(duì)不只是為了應(yīng)付八股文,更多的是考慮到在日常的 Spring 使用中遇到復(fù)雜問題時(shí)有沒有一個(gè)大致知曉的流程,可以快速定位問題,以及此類需求的技術(shù)實(shí)現(xiàn)方案是否能在以后的應(yīng)用開發(fā)中起到一定的指導(dǎo)作用,因?yàn)樗且环N設(shè)計(jì)方案的具體實(shí)現(xiàn)。

1. getBean 核心流程圖

小傅哥,getBean 核心流程圖

  • 整張圖就是 getBean 過程中涉及到的類和核心流程用到的方法以及操作的內(nèi)容。如果你能把整張圖全理解了,那么基本也就看懂了 getBean 的全過程。
  • 本張圖可能會(huì)因?yàn)榫W(wǎng)絡(luò)壓縮變得不清晰,可以通過關(guān)注公眾號(hào):bugstack蟲洞棧,回復(fù):圖稿,獲取。

接下來,我們就依次的把關(guān)于獲取 Bean 實(shí)例的重點(diǎn)代碼列舉出來做分析,讀者伙伴也可以結(jié)合流程圖一起看,這樣會(huì)更方便理解。

2. getBean 從哪開始讀源碼

 
 
 
 
  1. @Test 
  2. public void test_getBean() { 
  3.     BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config.xml"); 
  4.     UserDao userDao = beanFactory.getBean("userDao", UserDao.class); 
  5.     logger.info("獲取 Bean:{}", userDao); 

在日常應(yīng)用到 Spring 的開發(fā)中基本都是基于注解,幾乎不會(huì)自己去使用 beanFactory.getBean 的方式去獲取一個(gè) Bean 實(shí)例。

所以在你學(xué)習(xí)的時(shí)候如果找不到查看 getBean 源碼的入口,也不方便調(diào)試熟悉源碼時(shí),可以寫這樣一個(gè)單元測(cè)試類,點(diǎn)入到 getBean 就可以閱讀源碼了。

3. getBean 源碼全局預(yù)覽

源碼位置:AbstractBeanFactory -> getBean() -> doGetBean()

 
 
 
 
  1. @Override 
  2. public  T getBean(String name, Class requiredType) throws BeansException {  
  3.     // getBean 就像你的領(lǐng)導(dǎo)其實(shí)沒做啥,都在 doGetBean 里 
  4.  return doGetBean(name, requiredType, null, false); 
 
 
 
 
  1. protected  T doGetBean(final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) 
  2.   throws BeansException {      
  3.      
  4.     // 處理別名BeanName、處理帶&符的工廠BeanName 
  5.  final String beanName = transformedBeanName(name); 
  6.  Object bean;   
  7.  
  8.  // 先嘗試從緩存中獲取Bean實(shí)例,這個(gè)位置就是三級(jí)緩存解決循環(huán)依賴的方法 
  9.  Object sharedInstance = getSingleton(beanName);    
  10.  
  11.  if (sharedInstance != null && args == null) { 
  12.   if (logger.isDebugEnabled()) { 
  13.    if (isSingletonCurrentlyInCreation(beanName)) { 
  14.     logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + 
  15.       "' that is not fully initialized yet - a consequence of a circular reference"); 
  16.    } 
  17.    else { 
  18.     logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); 
  19.    } 
  20.   }         
  21.          
  22.         // 1. 如果 sharedInstance 是普通的 Bean 實(shí)例,則下面的方法會(huì)直接返回 
  23.         // 2. 如果 sharedInstance 是工廠Bean類型,則需要獲取 getObject 方法,可以參考關(guān)于 FactoryBean 的實(shí)現(xiàn)類  
  24.   bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 
  25.  } 
  26.  else { 
  27.    
  28.         // 循環(huán)依賴有三種,setter注入、多實(shí)例和構(gòu)造函數(shù),Spring 只能解決 setter 注入,所以這里是 Prototype 則會(huì)拋出異常 
  29.   if (isPrototypeCurrentlyInCreation(beanName)) { 
  30.    throw new BeanCurrentlyInCreationException(beanName); 
  31.   }     
  32.  
  33.   // 1. 父 bean 工廠存在 
  34.         // 2. 當(dāng)前 bean 不存在于當(dāng)前bean工廠,則到父工廠查找 bean 實(shí)例 
  35.   BeanFactory parentBeanFactory = getParentBeanFactory(); 
  36.   if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { 
  37.    // 獲取 name 對(duì)應(yīng)的 beanName,如果 name 是以 & 開頭,則返回 & + beanName 
  38.    String nameToLookup = originalBeanName(name);          
  39.              
  40.             // 根據(jù) args 參數(shù)是否為空,調(diào)用不同的父容器方法獲取 bean 實(shí)例 
  41.    if (args != null) { 
  42.     return (T) parentBeanFactory.getBean(nameToLookup, args); 
  43.    } 
  44.    else { 
  45.     return parentBeanFactory.getBean(nameToLookup, requiredType); 
  46.    } 
  47.   }        
  48.  
  49.         // 1. typeCheckOnly,用于判斷調(diào)用 getBean 方法時(shí),是否僅是做類型檢查 
  50.         // 2. 如果不是只做類型檢查,就會(huì)調(diào)用 markBeanAsCreated 進(jìn)行記錄 
  51.   if (!typeCheckOnly) { 
  52.    markBeanAsCreated(beanName); 
  53.   } 
  54.   try {     
  55.      
  56.             // 從容器 getMergedLocalBeanDefinition 獲取 beanName 對(duì)應(yīng)的 GenericBeanDefinition,轉(zhuǎn)換為 RootBeanDefinition 
  57.    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);  
  58.             // 檢查當(dāng)前創(chuàng)建的 bean 定義是否為抽象 bean 定義 
  59.    checkMergedBeanDefinition(mbd, beanName, args); 
  60.     
  61.             // 處理使用了 depends-on 注解的依賴創(chuàng)建 bean 實(shí)例 
  62.    String[] dependsOn = mbd.getDependsOn(); 
  63.    if (dependsOn != null) { 
  64.     for (String dep : dependsOn) {    
  65.                     // 監(jiān)測(cè)是否存在 depends-on 循環(huán)依賴,若存在則會(huì)拋出異常 
  66.      if (isDependent(beanName, dep)) { 
  67.       throw new BeanCreationException(mbd.getResourceDescription(), beanName, 
  68.         "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); 
  69.      }        
  70.                      
  71.                     // 注冊(cè)依賴記錄 
  72.      registerDependentBean(dep, beanName); 
  73.      try {     
  74.          // 加載 depends-on 依賴(dep 是 depends-on 縮寫) 
  75.       getBean(dep); 
  76.      } 
  77.      catch (NoSuchBeanDefinitionException ex) { 
  78.       throw new BeanCreationException(mbd.getResourceDescription(), beanName, 
  79.         "'" + beanName + "' depends on missing bean '" + dep + "'", ex); 
  80.      } 
  81.     } 
  82.    }   
  83.  
  84.    // 創(chuàng)建單例 bean 實(shí)例 
  85.    if (mbd.isSingleton()) {     
  86.  
  87.        // 把 beanName 和 new ObjectFactory 匿名內(nèi)部類傳入回調(diào) 
  88.     sharedInstance = getSingleton(beanName, new ObjectFactory() { 
  89.      @Override 
  90.      public Object getObject() throws BeansException { 
  91.       try {     
  92.                             // 創(chuàng)建 bean 
  93.        return createBean(beanName, mbd, args); 
  94.       } 
  95.       catch (BeansException ex) { 
  96.        // 創(chuàng)建失敗則銷毀 
  97.        destroySingleton(beanName); 
  98.        throw ex; 
  99.       } 
  100.      } 
  101.     }); 
  102.     bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 
  103.    }       
  104.             // 創(chuàng)建其他類型的 bean 實(shí)例 
  105.    else if (mbd.isPrototype()) { 
  106.     // It's a prototype -> create a new instance. 
  107.     Object prototypeInstance = null; 
  108.     try { 
  109.      beforePrototypeCreation(beanName); 
  110.      prototypeInstance = createBean(beanName, mbd, args); 
  111.     } 
  112.     finally { 
  113.      afterPrototypeCreation(beanName); 
  114.     } 
  115.     bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 
  116.    } 
  117.    else { 
  118.     String scopeName = mbd.getScope(); 
  119.     final Scope scope = this.scopes.get(scopeName); 
  120.     if (scope == null) { 
  121.      throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); 
  122.     } 
  123.     try { 
  124.      Object scopedInstance = scope.get(beanName, new ObjectFactory() { 
  125.       @Override 
  126.       public Object getObject() throws BeansException { 
  127.        beforePrototypeCreation(beanName); 
  128.        try { 
  129.         return createBean(beanName, mbd, args); 
  130.        } 
  131.        finally { 
  132.         afterPrototypeCreation(beanName); 
  133.        } 
  134.       } 
  135.      }); 
  136.      bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 
  137.     } 
  138.     catch (IllegalStateException ex) { 
  139.      throw new BeanCreationException(beanName, 
  140.        "Scope '" + scopeName + "' is not active for the current thread; consider " + 
  141.        "defining a scoped proxy for this bean if you intend to refer to it from a singleton", 
  142.        ex); 
  143.     } 
  144.    } 
  145.   } 
  146.   catch (BeansException ex) { 
  147.    cleanupAfterBeanCreationFailure(beanName); 
  148.    throw ex; 
  149.   } 
  150.  } 
  151.  // 如果需要類型轉(zhuǎn)換,這里會(huì)進(jìn)行操作 
  152.  if (requiredType != null && bean != null && !requiredType.isInstance(bean)) { 
  153.   try { 
  154.    return getTypeConverter().convertIfNecessary(bean, requiredType); 
  155.   } 
  156.   catch (TypeMismatchException ex) { 
  157.    if (logger.isDebugEnabled()) { 
  158.     logger.debug("Failed to convert bean '" + name + "' to required type '" + 
  159.       ClassUtils.getQualifiedName(requiredType) + "'", ex); 
  160.    } 
  161.    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 
  162.   } 
  163.  }     
  164.  
  165.     // 返回 Bean 
  166.  return (T) bean; 
  167. 綜上基本就是 getBean 過程涉及到的核心處理方法,基本包括;

    • transformedBeanName,處理別名BeanName、處理帶&符的工廠BeanName。
    • getSingleton,先嘗試從緩存中獲取Bean實(shí)例,這個(gè)位置就是三級(jí)緩存解決循環(huán)依賴的方法。
    • getObjectForBeanInstance,如果 sharedInstance 是普通的 Bean 實(shí)例,則下面的方法會(huì)直接返回。另外 sharedInstance 是工廠Bean類型,則需要獲取 getObject 方法,可以參考關(guān)于 FactoryBean 的實(shí)現(xiàn)類。
    • isPrototypeCurrentlyInCreation,循環(huán)依賴有三種,setter注入、多實(shí)例和構(gòu)造函數(shù),Spring 只能解決 setter 注入,所以這里是 Prototype 則會(huì)拋出異常。
    • getParentBeanFactory,父 bean 工廠存在,當(dāng)前 bean 不存在于當(dāng)前bean工廠,則到父工廠查找 bean 實(shí)例。
    • originalBeanName,獲取 name 對(duì)應(yīng)的 beanName,如果 name 是以 & 開頭,則返回 & + beanName
    • args != null,根據(jù) args 參數(shù)是否為空,調(diào)用不同的父容器方法獲取 bean 實(shí)例
    • !typeCheckOnly,typeCheckOnly,用于判斷調(diào)用 getBean 方法時(shí),是否僅是做類型檢查,如果不是只做類型檢查,就會(huì)調(diào)用 markBeanAsCreated 進(jìn)行記錄
    • mbd.getDependsOn,處理使用了 depends-on 注解的依賴創(chuàng)建 bean 實(shí)例
    • isDependent,監(jiān)測(cè)是否存在 depends-on 循環(huán)依賴,若存在則會(huì)拋出異常
    • registerDependentBean,注冊(cè)依賴記錄
    • getBean(dep),加載 depends-on 依賴(dep 是 depends-on 縮寫)
    • mbd.isSingleton(),創(chuàng)建單例 bean 實(shí)例
    • mbd.isPrototype(),創(chuàng)建其他類型的 bean 實(shí)例
    • return (T) bean,返回 Bean 實(shí)例

    4. beanName 轉(zhuǎn)換操作

    處理 & 符:transformedBeanName() -> BeanFactoryUtils.transformedBeanName(name)

     
     
     
     
    1. public static String transformedBeanName(String name) { 
    2.  Assert.notNull(name, "'name' must not be null"); 
    3.  String beanName = name; 
    4.  while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { 
    5.   beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); 
    6.  } 
    7.  return beanName; 
    • 使用 FactoryBean 創(chuàng)建出的對(duì)象,會(huì)在 DefaultListableBeanFactory 初始化的時(shí)候,使用 getBean(FACTORY_BEAN_PREFIX + beanName) 給 beanName 加上 & (String FACTORY_BEAN_PREFIX = "&")
    • 這里是使用 while 循環(huán)逐步的把 & 去掉,只要截取首個(gè)字符是 & 符,就繼續(xù)循環(huán)截取。&&&userService -> &&userService -> &userService -> userService

    別名轉(zhuǎn)換:transformedBeanName() -> canonicalName

     
     
     
     
    1. public String canonicalName(String name) { 
    2.  String canonicalName = name; 
    3.  // Handle aliasing... 
    4.  String resolvedName; 
    5.  do { 
    6.   resolvedName = this.aliasMap.get(canonicalName); 
    7.   if (resolvedName != null) { 
    8.    canonicalName = resolvedName; 
    9.   } 
    10.  } 
    11.  while (resolvedName != null); 
    12.  return canonicalName; 
    13. }
     
     
     
     
    1.  
    2.  
    3.  

    首先 Spring 對(duì) Bean 的存放并不會(huì)使用別名作為Map中的key,所以遇到所有別名獲取 Bean 都需要查到對(duì)應(yīng)原來名字,才可以。如果你知道這個(gè)事,是不遇到此類問題時(shí),就知道從哪下手查了

    do...while 循環(huán)會(huì)依次像鏈條一樣不斷的尋找別名對(duì)應(yīng)的名稱,直到當(dāng)前這個(gè)名稱沒有別名了,就返回對(duì)應(yīng) BeanName

    5. depends-on 依賴 Bean

     
     
     
     
    1. protected boolean isDependent(String beanName, String dependentBeanName) { 
    2.  synchronized (this.dependentBeanMap) { 
    3.   return isDependent(beanName, dependentBeanName, null); 
    4.  } 
    5.  
    6.  
    7.  

    isDependent 處理的是使用了 depends-on 配置的 Bean 定義。

     
     
     
     
    1. private boolean isDependent(String beanName, String dependentBeanName, Set alread 
    2.  if (alreadySeen != null && alreadySeen.contains(beanName)) { 
    3.   return false; 
    4.  } 
    5.  String canonicalName = canonicalName(beanName); 
    6.  Set dependentBeans = this.dependentBeanMap.get(canonicalName); 
    7.  if (dependentBeans == null) { 
    8.   return false; 
    9.  } 
    10.  if (dependentBeans.contains(dependentBeanName)) { 
    11.   return true; 
    12.  } 
    13.  for (String transitiveDependency : dependentBeans) { 
    14.   if (alreadySeen == null) { 
    15.    alreadySeen = new HashSet(); 
    16.   } 
    17.   alreadySeen.add(beanName); 
    18.   if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) { 
    19.    return true; 
    20.   } 
    21.  } 
    22.  return false; 
    • alreadySeen != null,監(jiān)測(cè)已經(jīng)依賴的 Bean
    • canonicalName,處理別名配置,找到最原來是的 BeanName
    • SetdependentBeans,獲取依賴的 Bean 集合
    • for 循環(huán)遞歸檢測(cè)依賴的 Bean,并添加到 alreadySeen 中

    AbstractBeanFactory -> registerDependentBean(dep, beanName) -> DefaultSingletonBeanRegistry

     
     
     
     
    1. public void registerDependentBean(String beanName, String dependentBeanName) { 
    2.  String canonicalName = canonicalName(beanName);   
    3.  
    4.  synchronized (this.dependentBeanMap) { 
    5.   Set dependentBeans = this.dependentBeanMap.get(canonicalName); 
    6.   if (dependentBeans == null) { 
    7.    dependentBeans = new LinkedHashSet(8); 
    8.    this.dependentBeanMap.put(canonicalName, dependentBeans); 
    9.   } 
    10.   dependentBeans.add(dependentBeanName); 
    11.  }    
    12.  
    13.  synchronized (this.dependenciesForBeanMap) { 
    14.   Set dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName 
    15.   if (dependenciesForBean == null) { 
    16.    dependenciesForBean = new LinkedHashSet(8); 
    17.    this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean); 
    18.   } 
    19.   dependenciesForBean.add(canonicalName); 
    20.  } 
    • canonicalName(beanName),獲取原始的 beanName
    • synchronized (this.dependentBeanMap),添加
    • synchronized (this.dependenciesForBeanMap),添加

    最后:getBean(dep),就可以獲取到 depends-on 依賴的 Bean 了

    6. 處理單實(shí)例 Bean

    AbstractBeanFactory -> mbd.isSingleton()

     
     
     
     
    1. if (mbd.isSingleton()) { 
    2.  sharedInstance = getSingleton(beanName, new ObjectFactory() { 
    3.   @Override 
    4.   public Object getObject() throws BeansException { 
    5.    try { 
    6.     return createBean(beanName, mbd, args); 
    7.    } 
    8.    catch (BeansException ex) { 
    9.     destroySingleton(beanName); 
    10.     throw ex; 
    11.    } 
    12.   } 
    13.  }); 
    14.  bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 
    15. 這一部分是使用 beanName 和 singletonFactory 匿名內(nèi)部類傳入等待回調(diào)的方式創(chuàng)建單實(shí)例 Bean 實(shí)例

       
       
       
       
      1. public Object getSingleton(String beanName, ObjectFactory singletonFactory) { 
      2.  Assert.notNull(beanName, "'beanName' 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.    catch (IllegalStateException ex) { 
      25.     singletonObject = this.singletonObjects.get(beanName); 
      26.     if (singletonObject == null) { 
      27.      throw ex; 
      28.     } 
      29.    } 
      30.    catch (BeanCreationException ex) { 
      31.     if (recordSuppressedExceptions) { 
      32.      for (Exception suppressedException : this.suppressedExceptions) { 
      33.       ex.addRelatedCause(suppressedException); 
      34.      } 
      35.     } 
      36.     throw ex; 
      37.    } 
      38.    finally { 
      39.     if (recordSuppressedExceptions) { 
      40.      this.suppressedExceptions = null; 
      41.     } 
      42.     afterSingletonCreation(beanName); 
      43.    } 
      44.    if (newSingleton) { 
      45.     addSingleton(beanName, singletonObject); 
      46.    } 
      47.   } 
      48.   return (singletonObject != NULL_OBJECT ? singletonObject : null); 
      49.  } 
      • this.singletonObjects.get(beanName),先嘗試從緩存池中獲取對(duì)象,沒有就繼續(xù)往下執(zhí)行
      • beforeSingletonCreation(beanName),標(biāo)記當(dāng)前 bean 被創(chuàng)建,如果有構(gòu)造函數(shù)注入的循環(huán)依賴會(huì)報(bào)錯(cuò)
      • singletonObject = singletonFactory.getObject(),創(chuàng)建 bean 過程就是調(diào)用 createBean() 方法
      • afterSingletonCreation(beanName),最后把標(biāo)記從集合中移除
      • addSingleton(beanName, singletonObject),新創(chuàng)建的會(huì)加入緩存集合

      7. 從緩存中獲取 bean 實(shí)例

      doCreateBean -> if (earlySingletonExposure) -> getSingleton(beanName, false)

       
       
       
       
      1. protected Object getSingleton(String beanName, boolean allowEarlyReference) { 
      2.     // 從 singletonObjects 獲取實(shí)例,singletonObjects 中緩存的實(shí)例都是完全實(shí)例化好的 bean,可以直接使用 
      3.  Object singletonObject = this.singletonObjects.get(beanName); 
      4.     // 如果 singletonObject 為空,則沒有創(chuàng)建或創(chuàng)建中 
      5.  if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { 
      6.         // 加鎖 
      7.   synchronized (this.singletonObjects) { 
      8.             // 單例緩存池中,沒有當(dāng)前beanName 
      9.    singletonObject = this.earlySingletonObjects.get(beanName); 
      10.    if (singletonObject == null && allowEarlyReference) { 
      11.     ObjectFactory singletonFactory = this.singletonFactories.get(beanName); 
      12.     if (singletonFactory != null) { 
      13.                     // 加入到三級(jí)緩存,暴漏早期對(duì)象用于解決三級(jí)緩存 
      14.      singletonObject = singletonFactory.getObject();   
      15.      this.earlySingletonObjects.put(beanName, singletonObject); 
      16.      this.singletonFactories.remove(beanName); 
      17.     } 
      18.    } 
      19.   } 
      20.  } 
      21.  return (singletonObject != NULL_OBJECT ? singletonObject : null); 
      • 其實(shí)這一段代碼主要就是使用三級(jí)緩存解決set注入循環(huán)依賴的,后面會(huì)單獨(dú)列一個(gè)章節(jié)對(duì)循環(huán)依賴做相關(guān)實(shí)驗(yàn)驗(yàn)證
      • singletonObjects,用于存放初始化好的 bean 實(shí)例。
      • earlySingletonObjects,用于存放初始化中的 bean,來解決循環(huán)依賴。
      • singletonFactories,用于存放 bean 工廠,bean 工廠所生成的 bean 還沒有完成初始化 bean。

      8. FactoryBean 中獲取 bean 實(shí)例

      AbstractBeanFactory -> getObjectForBeanInstance(sharedInstance, name, beanName, null)

       
       
       
       
      1. protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { 
      2.      
      3.     // 如果 beanName 以 & 開頭,但 beanInstance 卻不是 FactoryBean,則會(huì)拋出異常 
      4.  if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { 
      5.   throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); 
      6.  } 
      7.  
      8.     // 這里判斷就是這個(gè) bean 是不是 FactoryBean,不是就直接返回了 
      9.  if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { 
      10.   return beanInstance; 
      11.  }    
      12.  
      13.  Object object = null; 
      14.  if (mbd == null) {     
      15.         // 如果 mbd 為空,則從緩存加載 bean(FactoryBean 生成的單例 bean 實(shí)例會(huì)緩存到 factoryBeanObjectCache 集合中,方便使用) 
      16.   object = getCachedObjectForFactoryBean(beanName); 
      17.  }    
      18.  
      19.  if (object == null) { 
      20.   // 到這,beanInstance 是 FactoryBean 類型,所以就強(qiáng)轉(zhuǎn)了 
      21.   FactoryBean factory = (FactoryBean) beanInstance; 
      22.   // mbd 為空且判斷 containsBeanDefinition 是否包含 beanName 
      23.   if (mbd == null && containsBeanDefinition(beanName)) {     
      24.             // 合并 BeanDefinition 
      25.    mbd = getMergedLocalBeanDefinition(beanName); 
      26.   }     
      27.   boolean synthetic = (mbd != null && mbd.isSynthetic());    
      28.         // 調(diào)用 getObjectFromFactoryBean 獲取實(shí)例  
      29.   object = getObjectFromFactoryBean(factory, beanName, !synthetic); 
      30.  } 
      31.  return object; 
      • (!(beanInstance instanceof FactoryBean),這里判斷就是這個(gè) bean 是不是 FactoryBean,不是就直接返回了
      • 如果 mbd 為空,則從緩存加載 bean(FactoryBean 生成的單例 bean 實(shí)例會(huì)緩存到 factoryBeanObjectCache 集合中,方便使用)
      • 調(diào)用 getObjectFromFactoryBean 獲取實(shí)例,這里會(huì)包括一部分對(duì)單例以及非單例的處理,以及最終返回 factory.getObject(); 對(duì)應(yīng)的 Bean 實(shí)例

      四、測(cè)試案例

      1. 別名

       
       
       
       
      1.  
      2.  
      3.  
      4.  
      5.  
      6. @Test 
      7. public void test_alias() { 
      8.     BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-alias.xml"); 
      9.     UserService userService = beanFactory.getBean("userService-alias02", UserService.class); 
      10.     logger.info("獲取 Bean 通過別名:{}", userService); 

      在單元測(cè)試 getBean 的時(shí)候,會(huì)看到它會(huì)把別名逐步處理掉,最終獲取到原有的 BeanName

      2. 依賴

       
       
       
       
      1.  
      2.  
      3. @Test 
      4. public void test_depends_on() { 
      5.     BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-depends-on.xml"); 
      6.     UserService userService = beanFactory.getBean(UserService.class, "userService"); 
      7.     logger.info("獲取 Bean:{}", userService.getUserDao()); 

      • 涉及到依賴會(huì)走到 dependsOn != null 下,獲取到依賴的 Bean 實(shí)例。

      3. BeanFactory

       
       
       
       
      1.  
      2. @Test 
      3. public void test_factory_bean() { 
      4.     BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-factory-bean.xml"); 
      5.     UserDao userDao = beanFactory.getBean("userDao", UserDao.class); 
      6.     logger.info("獲取 Bean:{}", userDao); 

      實(shí)現(xiàn) FactoryBean 的類會(huì)需要實(shí)現(xiàn) getObject 方法,所有此類的 Bean 最終都是獲取 getObject

      五、總結(jié)

      • 到這里關(guān)于 Spring IOC 獲取 Bean 的核心流程基本就全部介紹完了,整個(gè)篇章讓我們看到獲取一個(gè) Bean 的流程也是非常復(fù)雜的,涉及到了非常多的分支流程。之所有會(huì)有這么多的流程,就是我們前面介紹到的,因?yàn)?Spring 的 Bean 獲取需要滿足很多種情況。
      • 在學(xué)習(xí)的過程可以優(yōu)先按照 GetBean 流程圖進(jìn)行梳理,之后對(duì)照源碼按步驟分析,這樣的過程幾乎會(huì)消耗你1~2天的時(shí)間,但整個(gè)過程學(xué)習(xí)完,基本也就對(duì) GetBean 沒有什么陌生了。
      • 學(xué)習(xí)幾乎就是一個(gè)慢慢磨的過程,就像走迷宮一樣,雖然有時(shí)候會(huì)走錯(cuò)路,但那些錯(cuò)了的路也是知識(shí)學(xué)習(xí)的一部分。在編程的學(xué)習(xí)中不只是看結(jié)果,過程是更重要的,學(xué)會(huì)學(xué)習(xí)的方式更有意義。

      本文名稱:關(guān)于Spring中GetBean的全流程源碼解析
      分享地址:http://www.dlmjj.cn/article/ccceiss.html