乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      spring源碼關(guān)于循環(huán)引用的筆記

       昵稱61698454 2019-10-07

      最近因?yàn)樾枰ブvspring源碼就又讀了一遍spring源碼, 感嘆一下spring源碼的龐大和強(qiáng)大,這次再讀源碼收獲很多;
      隨筆記錄一點(diǎn)關(guān)于spring當(dāng)中的循環(huán)引用的的源碼分析
      文字篇幅較多如果看到錯(cuò)別字一定提醒筆者修改

      眾所周知spring在默認(rèn)單例的情況下是支持循環(huán)引用的,比如有如下代碼:

      IndexService和UserService是相互依賴的、循環(huán)依賴、循環(huán)引用
      @Service
      public class IndexService {
         //注入userService
         @Autowired
         UserService userService;
      
         //構(gòu)造方法
         public IndexService(){
            System.out.println("index init");
         }
      }
      
      
      @Service
      public class UserService {
         //注入 indexService
         @Autowired
         IndexService indexService;
         //構(gòu)造方法
         public UserService(){
            System.out.println("user init");
         }
      }
      

      這兩個(gè)類非常簡(jiǎn)單,就是相互引用了對(duì)方,也就是我們常常的說(shuō)的循環(huán)依賴,spring是允許這樣的循環(huán)依賴(前提是單例的情況下的)

      運(yùn)行這段代碼的結(jié)果下圖

      在這里插入圖片描述

      spring默認(rèn)是支持循環(huán)的依賴的?
      可能在一些非常高級(jí)的面試當(dāng)中,(比如阿里的面試)面試官會(huì)問(wèn)你為什么spring當(dāng)中默認(rèn)支持循環(huán)依賴?或者問(wèn)spring在哪里體現(xiàn)了默認(rèn)支持循環(huán)依賴。從上面的結(jié)果我們可以推導(dǎo)出來(lái)spring是默認(rèn)支持循環(huán)依賴的,但這僅僅是個(gè)結(jié)果,你不可能告訴面試官說(shuō)你寫(xiě)了個(gè)簡(jiǎn)單的demo從而說(shuō)明了他默認(rèn)支持,高級(jí)面試中最好是能通過(guò)源碼設(shè)計(jì)來(lái)說(shuō)明這個(gè)問(wèn)題。比如spring的循環(huán)依賴其實(shí)是可以關(guān)閉的,spring提供了api來(lái)關(guān)閉循環(huán)依賴的功能。當(dāng)然你也可以修改spring源碼來(lái)關(guān)閉這個(gè)功能,這里筆者為了逼格很高,就修改一下spring的源碼來(lái)關(guān)閉這個(gè)功能,關(guān)于如何直接調(diào)用spring提供的api來(lái)直接關(guān)閉循環(huán)引用功能可以和私下問(wèn)筆者

      下圖是我修改后的spring源碼

      我加了一行setAllowCircularReferences(false);

      在這里插入圖片描述
      當(dāng)我修改spring源碼關(guān)閉循環(huán)引用功能之后代碼便會(huì)出異常

      在這里插入圖片描述

      那么為什么setAllowCircularReferences(false);會(huì)關(guān)閉循環(huán)依賴呢?首要明白spring的循環(huán)依賴是怎么做到的呢?spring源碼當(dāng)中是如何處理循環(huán)依賴的?
      我們來(lái)分析一下spring循環(huán)依賴這塊的源碼 其實(shí)所謂的循環(huán)依賴無(wú)非就是屬性注入,或者就是大家常常說(shuō)的自動(dòng)注入,
      故而我們需要去研究spring自動(dòng)注入的源碼

      下面筆者介紹一下spring創(chuàng)建一個(gè)bean的流程,通過(guò)源碼結(jié)合在idea當(dāng)中debug截圖來(lái)說(shuō)明

      1、main方法,初始化spring容器,在初始化容器之后默認(rèn)的單例bean已經(jīng)實(shí)例化完成了,也就是說(shuō)spring的默認(rèn)單例bean創(chuàng)建流程、和所謂自動(dòng)注入的功能都在容器初始化的過(guò)程中。故而我們需要研究這個(gè)容器初始化過(guò)程、在哪里體現(xiàn)了自動(dòng)注入;
      進(jìn)入AnnotationConfigApplicationContext類的構(gòu)造方法

      在這里插入圖片描述

      2、在構(gòu)造方法中調(diào)用了refresh方法,查看refresh方法

      在這里插入圖片描述

      3、refresh方法當(dāng)中調(diào)用finishBeanFactoryInitialization方法來(lái)實(shí)例化所有掃描出來(lái)的類
      在這里插入圖片描述

      4、finishBeanFactoryInitialization方法當(dāng)中調(diào)用preInstantiateSingletons初始化掃描出來(lái)的類
      在這里插入圖片描述

      5、preInstantiateSingletons方法經(jīng)過(guò)一系列判斷之后會(huì)調(diào)用getBean方法去實(shí)例化掃描出來(lái)的類
      在這里插入圖片描述
      6、getBean方法就是個(gè)空殼方法,調(diào)用了doGetBean方法

      在這里插入圖片描述

      doGetBean方法內(nèi)容有點(diǎn)多,這個(gè)方法非常重要,不僅僅針對(duì)循環(huán)依賴,
      甚至整個(gè)spring bean生命周期中這個(gè)方法也有著舉足輕重的地位,讀者可以認(rèn)真看看筆者的分析。需要說(shuō)明的是我為了更好的說(shuō)清楚這個(gè)方法,我把代碼放到文章里面進(jìn)行分析;但是刪除了一些無(wú)用的代碼;比如日志的記錄這些無(wú)關(guān)緊要的代碼。下面重點(diǎn)說(shuō)這個(gè)doGetBean方法

      protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
          
          //這個(gè)方法非常重要,但是和筆者今天要分析的循環(huán)依賴沒(méi)什么很大的關(guān)系
          //讀者可以簡(jiǎn)單的認(rèn)為就是對(duì)beanName做一個(gè)校驗(yàn)特殊字符串的功能
          //我會(huì)在下次更新博客的時(shí)候重點(diǎn)討論這個(gè)方法
          //transformedBeanName(name)這里的name就是bean的名字
         final String beanName = transformedBeanName(name);
         //定義了一個(gè)對(duì)象,用來(lái)存將來(lái)返回出來(lái)的bean
         Object bean;
         // Eagerly check singleton cache for manu  ally registered singletons.
         /**
          * 注意這是第一次調(diào)用getSingleton方法,下面spring還會(huì)調(diào)用一次
          * 但是兩次調(diào)用的不是同一個(gè)方法;屬于方法重載
          * 第一次 getSingleton(beanName) 也是循環(huán)依賴最重要的方法
          * 關(guān)于getSingleton(beanName)具體代碼分析可以參考筆者后面的分析
          * 這里給出這個(gè)方法的總結(jié)
          * 首先spring會(huì)去單例池去根據(jù)名字獲取這個(gè)bean,單例池就是一個(gè)map
          * 如果對(duì)象被創(chuàng)建了則直接從map中拿出來(lái)并且返回
          * 但是問(wèn)題來(lái)了,為什么spring在創(chuàng)建一個(gè)bean的時(shí)候會(huì)去獲取一次呢?
          * 因?yàn)樽鳛榇a的書(shū)寫(xiě)者肯定知道這個(gè)bean這個(gè)時(shí)候沒(méi)有創(chuàng)建?為什么需要get一次呢?
          * 關(guān)于這個(gè)問(wèn)題其實(shí)原因比較復(fù)雜,需要讀者對(duì)spring源碼設(shè)計(jì)比較精通
          * 筆者不準(zhǔn)備來(lái)針對(duì)這個(gè)原因大書(shū)特書(shū),稍微解釋一下吧
          * 我們可以分析doGetBean這個(gè)方法,顧名思義其實(shí)是用來(lái)獲取bean的
          * 為什么創(chuàng)建bean會(huì)調(diào)用這個(gè)doGetBean方法呢?難道是因?yàn)閟pring作者疏忽,獲取亂起名字
          * 顯然不是,spring的源碼以其書(shū)寫(xiě)優(yōu)秀、命名優(yōu)秀而著名,那么怎么解釋這個(gè)方法呢?
          * 其實(shí)很簡(jiǎn)單doGetBean這個(gè)方法不僅僅在創(chuàng)建bean的時(shí)候會(huì)被調(diào)用,在getBean的時(shí)候也會(huì)調(diào)用
          * 他是創(chuàng)建bean和getBean通用的方法。但是這只是解釋了這個(gè)方法的名字意義
          * 并么有解釋這個(gè)方法為什么會(huì)在創(chuàng)建bean的時(shí)候調(diào)用
          * 筆者前面已經(jīng)說(shuō)過(guò)原因很復(fù)雜,和本文有關(guān)的就是因?yàn)檠h(huán)引用
          * 由于循環(huán)引用需要在創(chuàng)建bean的過(guò)程中去獲取被引用的那個(gè)類
          * 而被引用的這個(gè)類如果沒(méi)有創(chuàng)建,則會(huì)調(diào)用createBean來(lái)創(chuàng)建這個(gè)bean
          * 在創(chuàng)建這個(gè)被引用的bean的過(guò)程中會(huì)判斷這個(gè)bean的對(duì)象有沒(méi)有實(shí)例化
          * bean的對(duì)象?什么意思呢?
          * 為了方便閱讀,請(qǐng)讀者一定記住兩個(gè)概念;什么是bean,什么是對(duì)象
          * 筆者以為一個(gè)對(duì)象和bean是有區(qū)別的
          * 對(duì)象:只要類被實(shí)例化就可以稱為對(duì)象
          * bean:首先得是一個(gè)對(duì)象,然后這個(gè)對(duì)象需要經(jīng)歷一系列的bean生命周期
          * 最后把這個(gè)對(duì)象put到單例池才能算一個(gè)bean
          * 讀者千萬(wàn)注意,筆者下文中如果寫(xiě)到bean和寫(xiě)到對(duì)象不是隨意寫(xiě)的
          * 是和這里的解釋有關(guān)系的;重點(diǎn)一定要注意;一定;一定;
          * 簡(jiǎn)而言之就是spring先new一個(gè)對(duì)象,繼而對(duì)這個(gè)對(duì)象進(jìn)行生命周期回調(diào)
          * 接著對(duì)這個(gè)對(duì)象進(jìn)行屬性填充,也是大家說(shuō)的自動(dòng)注入
          * 然后在進(jìn)行AOP判斷等等;這一些操作簡(jiǎn)稱----spring生命周期
          * 所以一個(gè)bean是一個(gè)經(jīng)歷了spring周期的對(duì)象,和一個(gè)對(duì)象有區(qū)別
          * 再回到前面說(shuō)的循環(huán)引用,首先spring掃描到一個(gè)需要被實(shí)例化的類A
          * 于是spring就去創(chuàng)建A;A=new A-a;new A的過(guò)程會(huì)調(diào)用getBean("a"));
          * 所謂的getBean方法--核心也就是筆者現(xiàn)在寫(xiě)注釋的這個(gè)getSingleton(beanName)
          * 這個(gè)時(shí)候get出來(lái)肯定為空?為什么是空呢?我寫(xiě)這么多注釋就是為了解釋這個(gè)問(wèn)題?
          * 可能有的讀者會(huì)認(rèn)為getBean就是去容器中獲取,所以肯定為空,其實(shí)不然,接著往下看
          * 如果getA等于空;spring就會(huì)實(shí)例化A;也就是上面的new A
          * 但是在實(shí)例化A的時(shí)候會(huì)再次調(diào)用一下 
          * getSingleton(String beanName, ObjectFactory<?> singletonFactory)
          * 筆者上面說(shuō)過(guò)現(xiàn)在寫(xiě)的注釋給getSingleton(beanName)
          * 也即是第一次調(diào)用getSingleton(beanName)
          * 實(shí)例化一共會(huì)調(diào)用兩次getSingleton方法;但是是重載
          * 第二次調(diào)用getSingleton方法的時(shí)候spring會(huì)在一個(gè)set集合當(dāng)中記錄一下這個(gè)類正在被創(chuàng)建
          * 這個(gè)一定要記住,在調(diào)用完成第一次getSingleton完成之后
          * spring判讀這個(gè)類沒(méi)有創(chuàng)建,然后調(diào)用第二次getSingleton
          * 在第二次getSingleton里面記錄了一下自己已經(jīng)開(kāi)始實(shí)例化這個(gè)類
          * 這是循環(huán)依賴做的最牛逼的地方,兩次getSingleton的調(diào)用
          * 也是回答面試時(shí)候關(guān)于循環(huán)依賴必須要回答道的地方;
          * 需要說(shuō)明的spring實(shí)例化一個(gè)對(duì)象底層用的是反射;
          * spring實(shí)例化一個(gè)對(duì)象的過(guò)程非常復(fù)雜,需要推斷構(gòu)造方法等等;
          * 這里筆者先不討論這個(gè)過(guò)程,以后有機(jī)會(huì)更新一下
          * 讀者可以理解spring直接通過(guò)new關(guān)鍵字來(lái)實(shí)例化一個(gè)對(duì)象
          * 但是這個(gè)時(shí)候?qū)ο骯僅僅是一個(gè)對(duì)象,還不是一個(gè)完整的bean
          * 接著讓這個(gè)對(duì)象去完成spring的bean的生命周期
          * 過(guò)程中spring會(huì)判斷容器是否允許循環(huán)引用,判斷循環(huán)引用的代碼筆者下面會(huì)分析
          * 前面說(shuō)過(guò)spring默認(rèn)是支持循環(huán)引用的,筆者后面解析這個(gè)判斷的源碼也是spring默認(rèn)支持循環(huán)引用的證據(jù)
          * 如果允許循環(huán)依賴,spring會(huì)把這個(gè)對(duì)象(還不是bean)臨時(shí)存起來(lái),放到一個(gè)map當(dāng)中
          * 注意這個(gè)map和單例池是兩個(gè)map,在spring源碼中單例池的map叫做 singletonObjects
          * 而這個(gè)存放臨時(shí)對(duì)象的map叫做singletonFactories
          * 當(dāng)然spring還有一個(gè)存放臨時(shí)對(duì)象的map叫做earlySingletonObjects
          * 所以一共是三個(gè)map,有些博客或者書(shū)籍人也叫做三級(jí)緩存
          * 為什么需要三個(gè)map呢?先來(lái)了解這三個(gè)map到底都緩存了什么
          * 第一個(gè)map singletonObjects 存放的單例的bean
          * 第二個(gè)map singletonFactories 存放的臨時(shí)對(duì)象(沒(méi)有完整springBean生命周期的對(duì)象)
          * 第三個(gè)map earlySingletonObjects 存放的臨時(shí)對(duì)象(沒(méi)有完整springBean生命周期的對(duì)象)
          * 筆者為了讓大家不懵逼這里吧第二個(gè)和第三個(gè)map功能寫(xiě)成了一模一樣
          * 其實(shí)第二個(gè)和第三個(gè)map會(huì)有不一樣的地方,但這里不方便展開(kāi)講,下文會(huì)分析
          * 讀者姑且認(rèn)為這兩個(gè)map是一樣的
          * 第一個(gè)map主要為了直接緩存創(chuàng)建好的bean;方便程序員去getBean;很好理解
          * 第二個(gè)和第三個(gè)主要為了循環(huán)引用;為什么為了方便循環(huán)引用,接著往下看
          * 把對(duì)象a緩存到第二個(gè)map之后,會(huì)接著完善生命周期;
          * 當(dāng)然spring bean的生命周期很有很多步驟;本文先不詳細(xì)討論;
          * 后面的博客筆者再更新;
          * 當(dāng)進(jìn)行到對(duì)象a的屬性填充的這一周期的時(shí)候,發(fā)覺(jué)a依賴了一個(gè)B類
          * 所以spring就會(huì)去判斷這個(gè)B類到底有沒(méi)有bean在容器當(dāng)中
          * 這里的判斷就是從第一個(gè)map即單例池當(dāng)中去拿一個(gè)bean
          * 后面我會(huì)通過(guò)源碼來(lái)證明是從第一個(gè)map中拿一個(gè)bean的
          * 假設(shè)沒(méi)有,那么spring會(huì)先去調(diào)用createBean創(chuàng)建這個(gè)bean
          * 于是又回到和創(chuàng)建A一樣的流程,在創(chuàng)建B的時(shí)候同樣也會(huì)去getBean("B");
          * getBean核心也就是筆者現(xiàn)在寫(xiě)注釋的這個(gè)getSingleton(beanName)方法
          * 下面我重申一下:因?yàn)槭侵攸c(diǎn)
          * 這個(gè)時(shí)候get出來(lái)肯定為空?為什么是空呢?我寫(xiě)這么多注釋就是為了解釋這個(gè)問(wèn)題?
          * 可能有的讀者會(huì)認(rèn)為getBean就是去容器中獲?。?    * 所以肯定為空,其實(shí)不然,接著往下看;
          * 第一次調(diào)用完getSingleton完成之后會(huì)調(diào)用第二次getSingleton
         * 第二次調(diào)用getSingleton同樣會(huì)在set集合當(dāng)中去記錄B正在被創(chuàng)建
         * 請(qǐng)筆者記住這個(gè)時(shí)候 set集合至少有兩個(gè)記錄了 A和B;
         * 如果為空就 b=new B();創(chuàng)建一個(gè)b對(duì)象;
         * 再次說(shuō)明一下關(guān)于實(shí)例化一個(gè)對(duì)象,spring做的很復(fù)雜,下次討論
         * 創(chuàng)建完B的對(duì)象之后,接著完善B的生命周期
         * 同樣也會(huì)判斷是否允許循環(huán)依賴,如果允許則把對(duì)象b存到第二個(gè)map當(dāng)中;
         * 提醒一下筆者這個(gè)時(shí)候第二個(gè)map當(dāng)中至少有兩個(gè)對(duì)象了,a和b
         * 接著繼續(xù)生命周期;當(dāng)進(jìn)行到b對(duì)象的屬性填充的時(shí)候發(fā)覺(jué)b需要依賴A
         * 于是就去容器看看A有沒(méi)有創(chuàng)建,說(shuō)白了就是從第一個(gè)map當(dāng)中去找a
         * 有人會(huì)說(shuō)不上A在前面創(chuàng)建了a嘛?注意那只是個(gè)對(duì)象,不是bean;
         * 還不在第一個(gè)map當(dāng)中 對(duì)所以b判定A沒(méi)有創(chuàng)建,于是就是去創(chuàng)建A;
         * 那么又再次回到了原點(diǎn)了,創(chuàng)建A的過(guò)程中;首先調(diào)用getBean("a")
         * 上文說(shuō)到getBean("a")的核心就是 getSingleton(beanName)
         * 上文也說(shuō)了get出來(lái)a==null;但是這次卻不等于空了
         * 這次能拿出一個(gè)a對(duì)象;注意是對(duì)象不是bean
         * 為什么兩次不同?原因在于getSingleton(beanName)的源碼
         * getSingleton(beanName)首先從第一個(gè)map當(dāng)中獲取bean
         * 這里就是獲取a;但是獲取不到;然后判斷a是不是等于空
         * 如果等于空則在判斷a是不是正在創(chuàng)建?什么叫做正在創(chuàng)建?
         * 就是判斷a那個(gè)set集合當(dāng)中有沒(méi)有記錄A;
         * 如果這個(gè)集合當(dāng)中包含了A則直接把a(bǔ)對(duì)象從map當(dāng)中g(shù)et出來(lái)并且返回
         * 所以這一次就不等于空了,于是B就可以自動(dòng)注入這個(gè)a對(duì)象了
         * 這個(gè)時(shí)候a還只是對(duì)象,a這個(gè)對(duì)象里面依賴的B還沒(méi)有注入
         * 當(dāng)b對(duì)象注入完成a之后,把B的周期走完,存到容器當(dāng)中
         * 存完之后繼續(xù)返回,返回到a注入b哪里?
         * 因?yàn)閎的創(chuàng)建時(shí)因?yàn)閍需要注入b;于是去get b
         * 當(dāng)b創(chuàng)建完成一個(gè)bean之后,返回b(b已經(jīng)是一個(gè)bean了)
         * 需要說(shuō)明的b是一個(gè)bean意味著b已經(jīng)注入完成了a;這點(diǎn)上面已經(jīng)說(shuō)明了
         * 由于返回了一個(gè)b,故而a也能注入b了;
         * 接著a對(duì)象繼續(xù)完成生命周期,當(dāng)走完之后a也在容器中了
         * 至此循環(huán)依賴搞定
         * 需要說(shuō)明一下上文提到的正在創(chuàng)建這種說(shuō)法并沒(méi)有官方支持
         * 是筆者自己的認(rèn)為;各位讀者可以自行給他取名字
         * 筆者是因?yàn)榇娣拍切┯涗浀膕et集合的名字叫做singletonsCurrentlyInCreation
         * 顧名思義,當(dāng)前正在創(chuàng)建的單例對(duì)象。。。。。
         * 還有上文提到的對(duì)象和bean的概念;也沒(méi)有官方支持
         * 也是筆者為了讓讀者更好的理解spring源碼而提出的個(gè)人概念
         * 但是如果你覺(jué)得這種方法確實(shí)能讓你更好的理解spring源碼
         * 那么請(qǐng)姑且相信筆者對(duì)spring源碼的理解,假設(shè)10個(gè)人相信就會(huì)有100個(gè)人相信
         * 繼而會(huì)有更多人相信,就會(huì)成為官方說(shuō)法,哈哈。
         * 以上是循環(huán)依賴的整個(gè)過(guò)程,其中g(shù)etSingleton(beanName)
         * 這個(gè)方法的存在至關(guān)重要
         * 最后說(shuō)明一下getSingleton(beanName)的源碼分析,下文會(huì)分析
         **/
          Object sharedInstance = getSingleton(beanName);
          
          
        /**
         * 如果sharedInstance不等于空直接返回
         * 當(dāng)然這里沒(méi)有直接返回而是調(diào)用了getObjectForBeanInstance
         * 關(guān)于這方法以后解釋,讀者可以認(rèn)為這里可以理解為
         * bean =sharedInstance; 然后方法最下面會(huì)返回bean
         * 什么時(shí)候不等于空?
         * 再容器初始化完成之后
         * 程序員直接調(diào)用getbean的時(shí)候不等于空
         * 什么時(shí)候等于空?
         * 上文已經(jīng)解釋過(guò)了,創(chuàng)建對(duì)象的時(shí)候調(diào)用就會(huì)等于空
         */  
         if (sharedInstance != null && args == null) {
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
         }
      
         else {
            /**
              * 判斷這個(gè)類是不是在創(chuàng)建過(guò)程中
              * 上文說(shuō)了,一個(gè)類是否在創(chuàng)建的過(guò)程中是第二次調(diào)用getSingleton中決定的
              * 這里還沒(méi)有執(zhí)行到,如果就在創(chuàng)建過(guò)程中則出異常
              * 
              **/
            //prototypesCurrentlyInCreation 需要聯(lián)系 getSingleton方法
            if (isPrototypeCurrentlyInCreation(beanName)) {
               throw new BeanCurrentlyInCreationException(beanName);
            }else{
                /**
                 * 需要說(shuō)明的筆者刪了很多和本文無(wú)用的代碼
                 * 意思就是源碼中執(zhí)行到這個(gè)if的時(shí)候有很多其他代碼
                 * 但是都是一些判斷,很本文需要討論的問(wèn)題關(guān)聯(lián)不大
                 * 這個(gè)if就是判斷當(dāng)前需要實(shí)例化的類是不是單例的
                 * spring默認(rèn)都是單例的,故而一般都成立的
                 * 接下來(lái)便是調(diào)用第二次 getSingleton
                 * 第二次會(huì)把當(dāng)前正在創(chuàng)建的類記錄到set集合
                 * 然后反射創(chuàng)建這個(gè)實(shí)例,并且走完生命周期
                 * 第二次調(diào)用getSingleton的源碼分析會(huì)在下文
                 **/
               if (mbd.isSingleton()) {
                  sharedInstance = getSingleton(beanName, () -> {
                     try {
                        //完成了目標(biāo)對(duì)象的創(chuàng)建
                        //如果需要代理,還完成了代理
                        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.
                        destroySingleton(beanName);
                        throw ex;
                     }
                  });
                  bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
               }
         return (T) bean;
      }
      

      第一次調(diào)用getSingleton的源碼分析 Object sharedInstance =
      getSingleton(beanName);

      //空殼方法
      public Object getSingleton(String beanName) {
          //重點(diǎn),一定要記住這里傳的是一個(gè)true,面試會(huì)考
         return getSingleton(beanName, true);
      }
      
      
      
      /**
      上面說(shuō)的true對(duì)應(yīng)這里的第二個(gè)參數(shù)boolean allowEarlyReference
      顧名思義 叫做允許循環(huán)引用,而spring在內(nèi)部調(diào)用這個(gè)方法的時(shí)候傳的true
      這也能說(shuō)明spring默認(rèn)是支持循環(huán)引用的,這也是需要講過(guò)面試官的
      但是你不能只講這一點(diǎn),后面我會(huì)總結(jié),這里先記著這個(gè)true
      這個(gè)allowEarlyReference也是支持spring默認(rèn)支持循環(huán)引用的其中一個(gè)原因
      **/
      protected Object getSingleton(String beanName, boolean allowEarlyReference) {
          /**
           首先spring會(huì)去第一個(gè)map當(dāng)中去獲取一個(gè)bean;說(shuō)白了就是從容器中獲取
           說(shuō)明我們?nèi)绻谌萜鞒跏蓟笳{(diào)用getBean其實(shí)就從map中去獲取一個(gè)bean
           假設(shè)是初始化A的時(shí)候那么這個(gè)時(shí)候肯定等于空,前文分析過(guò)這個(gè)map的意義
           **/
          Object singletonObject = this.singletonObjects.get(beanName);
             /**
             我們這里的場(chǎng)景是初始化對(duì)象A第一次調(diào)用這個(gè)方法
             這段代碼非常重要,首先從容器中拿,如果拿不到,再判斷這個(gè)對(duì)象是不是在set集合
             這里的set集合前文已經(jīng)解釋過(guò)了,就是判斷a是不是正在創(chuàng)建
             假設(shè)現(xiàn)在a不在創(chuàng)建過(guò)程,那么直接返回一個(gè)空,第一次getSingleton返回
             **/
         if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
               singletonObject = this.earlySingletonObjects.get(beanName);
               if (singletonObject == null && allowEarlyReference) {
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                     singletonObject = singletonFactory.getObject();
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
         return singletonObject;
      }
      

      第二次調(diào)用getSingleton sharedInstance = getSingleton(beanName, () ->
      代碼我做了刪減,刪了一些本本文無(wú)關(guān)的代碼

      public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
         synchronized (this.singletonObjects) {
          
             //首先也是從第一個(gè)map即容器中獲取
             //再次證明如果我們?cè)谌萜鞒跏蓟笳{(diào)用getBean其實(shí)就是從map當(dāng)中獲取一個(gè)bean
             //我們這里的場(chǎng)景是初始化對(duì)象A第一次調(diào)用這個(gè)方法
             //那么肯定為空
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                /**注意這行代碼,就是A的名字添加到set集合當(dāng)中
                也就是筆者說(shuō)的標(biāo)識(shí)A正在創(chuàng)建過(guò)程當(dāng)中
                這個(gè)方法比較簡(jiǎn)單我就不單獨(dú)分析了,直接在這里給出
                singletonsCurrentlyInCreation.add就是放到set集合當(dāng)中
                protected void beforeSingletonCreation(String beanName) {
                     if (!this.inCreationCheckExclusions.contains(beanName)
                      && !this.singletonsCurrentlyInCreation.add(beanName)) {
                        throw new BeanCurrentlyInCreationException(beanName);
                 }
              }
              **/
              
               beforeSingletonCreation(beanName);
               boolean newSingleton = false;
               try {
                   //這里便是創(chuàng)建一個(gè)bean的入口了
                   //spring會(huì)首先實(shí)例化一個(gè)對(duì)象,然后走生命周期
                   //走生命周期的時(shí)候前面說(shuō)過(guò)會(huì)判斷是否允許循環(huán)依賴
                   //如果允許則會(huì)把創(chuàng)建出來(lái)的這個(gè)對(duì)象放到第二個(gè)map當(dāng)中
                   //然后接著走生命周期當(dāng)他走到屬性填充的時(shí)候
                   //會(huì)去get一下B,因?yàn)樾枰畛銪,也就是大家認(rèn)為的自動(dòng)注入
                   //這些代碼下文分析,如果走完了生命周期
                  singletonObject = singletonFactory.getObject();
                  newSingleton = true;
               }
            }
            return singletonObject;
         }
      }
      

      如果允許則會(huì)把創(chuàng)建出來(lái)的這個(gè)對(duì)象放到第二個(gè)map當(dāng)中
      AbstractAutowireCapableBeanFactory#doCreateBean()方法部分代碼
      由于這個(gè)方法內(nèi)容過(guò)去多,我刪減了一些無(wú)用代碼 上面說(shuō)的 singletonObject =
      singletonFactory.getObject();
      會(huì)開(kāi)始創(chuàng)建bean調(diào)用AbstractAutowireCapableBeanFactory#doCreateBean() 在創(chuàng)建bean;
      下面分析這個(gè)方法

      protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {
      
         // Instantiate the bean.
         BeanWrapper instanceWrapper = null;
         if (mbd.isSingleton()) {
             //如果你bean指定需要通過(guò)factoryMethod來(lái)創(chuàng)建則會(huì)在這里被創(chuàng)建
             //如果讀者不知道上面factoryMethod那你就忽略這行代碼
             //你可以認(rèn)為你的A是一個(gè)普通類,不會(huì)再這里創(chuàng)建
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
         }
         if (instanceWrapper == null) {
             //這里就通過(guò)反射創(chuàng)建一個(gè)對(duì)象,注意是對(duì)象不是bean
             //這個(gè)createBeanInstance的方法過(guò)于復(fù)雜,本文不做分析
             //以后如果有更新再來(lái)分析這個(gè)代碼
             //讀者可以理解這里就是new了一個(gè)A對(duì)象
            instanceWrapper = createBeanInstance(beanName, mbd, args);
         }
         //得到new出來(lái)的A,為什么需要得到呢?因?yàn)锳new出來(lái)之后存到一個(gè)對(duì)象的屬性當(dāng)中
         final Object bean = instanceWrapper.getWrappedInstance();
         //重點(diǎn):面試會(huì)考
         //這里就是判斷是不是支持循環(huán)引用和是否單例以及bean是否在創(chuàng)建過(guò)程中
         //判斷循環(huán)引用的是&& this.allowCircularReferences
         //allowCircularReferences在spring源碼當(dāng)中默認(rèn)就是true
         // private boolean allowCircularReferences = true; 這是spring源碼中的定義
         //并且這個(gè)屬性上面spring寫(xiě)了一行非常重要的注釋
         // Whether to automatically try to resolve circular references between beans
         // 讀者自行翻譯,這是支持spring默認(rèn)循環(huán)引用最核心的證據(jù)
         //讀者一定要講給面試官,關(guān)于怎么講,我后面會(huì)總結(jié)
         boolean earlySingletonExposure = (mbd.isSingleton() 
             && this.allowCircularReferences &&
               isSingletonCurrentlyInCreation(beanName));
         //如果是單例,并且正在創(chuàng)建,并且是沒(méi)有關(guān)閉循環(huán)引用則執(zhí)行
         //所以spring原形是不支持循環(huán)引用的這是證據(jù),但是其實(shí)可以解決
         //怎么解決原形的循環(huán)依賴,筆者下次更新吧      
         if (earlySingletonExposure) {
             //這里就是這個(gè)創(chuàng)建出來(lái)的A 對(duì)象a 放到第二個(gè)map當(dāng)中
             //注意這里addSingletonFactory就是往map當(dāng)中put
             //需要說(shuō)明的是他的value并不是一個(gè)a對(duì)象
             //而是一段表達(dá)式,但是包含了這個(gè)對(duì)象的
             //所以上文說(shuō)的第二個(gè)map和第三個(gè)map的有點(diǎn)不同
             //第三個(gè)map是直接放的a對(duì)象(下文會(huì)講到第三個(gè)map的),
             //第二個(gè)放的是一個(gè)表達(dá)式包含了a對(duì)象
             //為什么需要放一個(gè)表達(dá)式?下文分析吧
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
         }
      
         // Initialize the bean instance.
         Object exposedObject = bean;
         try {
             //填充屬性,也就是所謂的自動(dòng)注入
             //這個(gè)代碼我同一張圖來(lái)說(shuō)明
            populateBean(beanName, mbd, instanceWrapper);
            exposedObject = initializeBean(beanName, exposedObject, mbd);
         }
         return exposedObject;
         }
      

      populateBean(beanName, mbd, instanceWrapper)截圖圖說(shuō)明
      在這里插入圖片描述

      當(dāng)A執(zhí)行到屬性填充的時(shí)候會(huì)調(diào)用AutowiredAnnotationBeanPostProcessor的postProcessProperties方法來(lái)完成填充或者叫做自動(dòng)注入b
      下圖有很多文字注釋,可以放大圖上的注釋

      在這里插入圖片描述

      填充B的時(shí)候先從容器中獲取B,這個(gè)時(shí)候b沒(méi)有創(chuàng)建則等于空,然后看B是不是正在創(chuàng)建,這個(gè)時(shí)候B只是執(zhí)行了第一次getSingleton故而不在第二個(gè)map當(dāng)中,所以返回空,返回空之后會(huì)執(zhí)行創(chuàng)建B的流程;執(zhí)行第二遍調(diào)用getSingleton的時(shí)候會(huì)把b標(biāo)識(shí)正在創(chuàng)建的過(guò)程中,也就是添加到那個(gè)set集合當(dāng)中;下圖做說(shuō)明

      在這里插入圖片描述

      創(chuàng)建B的流程和創(chuàng)建A差不多,把B放到set集合,標(biāo)識(shí)B正在創(chuàng)建,繼而實(shí)例化b對(duì)象,然后執(zhí)行生命周期流程,把創(chuàng)建的這個(gè)b對(duì)象放到第二個(gè)map當(dāng)中,這個(gè)時(shí)候map當(dāng)中已經(jīng)有了a,b兩個(gè)對(duì)象。
      然后執(zhí)行b對(duì)象的屬性填充或者叫自動(dòng)注入時(shí)候發(fā)覺(jué)需要依賴a,于是重復(fù)上面的getbean步驟,調(diào)用getSingleton方法;只不過(guò)現(xiàn)在a對(duì)象已經(jīng)可以獲取了故而把獲取出來(lái)的a對(duì)象、臨時(shí)對(duì)象注入給b對(duì)象,然后走完b的生命周期流程后返回b所表示bean,跟著把這個(gè)b所表示的bean注入給a對(duì)象,最后走完a對(duì)象的其他生命周期流程;循環(huán)依賴流程全部走完;但是好像沒(méi)有說(shuō)到第三個(gè)map,第三個(gè)map到底充當(dāng)了什么角色呢?
      這個(gè)知識(shí)點(diǎn)非常的重要,關(guān)于這個(gè)知識(shí)不少書(shū)籍和博客都說(shuō)錯(cuò)了,這也是寫(xiě)這篇文章的意義;筆者說(shuō)每次讀spring源碼都不一樣的收獲,這次最大的收獲便是這里了;我們先來(lái)看一下代碼;
      場(chǎng)景是這樣的,spring創(chuàng)建A,記住第一次創(chuàng)建A,過(guò)程中發(fā)覺(jué)需要依賴B,于是創(chuàng)建B,創(chuàng)建B的時(shí)候發(fā)覺(jué)需要依賴A,于是再一次創(chuàng)建–第二次創(chuàng)建A,下面代碼就是基于第二次創(chuàng)建的A來(lái)分析;第二次創(chuàng)建A的時(shí)候依然會(huì)調(diào)用getSingleton,先獲取一下a

      protected Object getSingleton(String beanName, boolean allowEarlyReference) {
          //先從第一個(gè)map獲取a這個(gè)bean,也就是單例池獲取
         Object singletonObject = this.singletonObjects.get(beanName);
         if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                //然后從第三個(gè)map當(dāng)中獲取a這個(gè)對(duì)象
               singletonObject = this.earlySingletonObjects.get(beanName);
               //如果第三個(gè)map獲取不到a對(duì)象,再看是否允許了循環(huán)引用
               //而這里的allowEarlyReference是true
               //為什么是true,上文說(shuō)了這個(gè)方法是spring自己調(diào)用的,他默認(rèn)傳了true
               if (singletonObject == null && allowEarlyReference) {
                   //然后從第二個(gè)map中獲取一個(gè)表達(dá)式
                   //這里要非常注意第二個(gè)map當(dāng)中存的不是一個(gè)單純的對(duì)象
                   //前面說(shuō)了第二個(gè)map當(dāng)中存的是一個(gè)表達(dá)式,你可以理解為存了一個(gè)工廠
                   //或者理解存了一個(gè)方法,方法里面有個(gè)參數(shù)就是這個(gè)對(duì)象
                   //安裝spring的命名來(lái)分析應(yīng)該理解為一個(gè)工廠singletonFactory
                   //一個(gè)能夠生成a對(duì)象的工廠
                   //那么他為什么需要這么一個(gè)工廠
                   //這里我先大概說(shuō)一下,是為了通過(guò)工廠來(lái)改變這個(gè)對(duì)象
                   //至于為什么要改變對(duì)象,下文我會(huì)分析
                   //當(dāng)然大部分情況下是不需要改變這個(gè)對(duì)象的
                   //讀者先可以考慮不需要改變這個(gè)對(duì)象,
                   //那么這個(gè)map里面存的工廠就生產(chǎn)就是這個(gè)原對(duì)象,那么和第三個(gè)map功能一樣
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                      //調(diào)用表達(dá)式,說(shuō)白了就是調(diào)用工廠的方法,然后改變對(duì)象
                      //我們假設(shè)對(duì)象不需要改變的情況那么返回了原對(duì)象就是a
                      //需要改變的情況我們下文再分享
                     singletonObject = singletonFactory.getObject();
                     //然后把這個(gè)對(duì)象放到第三個(gè)map當(dāng)中
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     //把這個(gè)對(duì)象、或者表達(dá)式、或者工廠從第二個(gè)map中移除
                     this.singletonFactories.remove(beanName);
                     //重點(diǎn):面試會(huì)考---為什么要放到第三個(gè)?為什么要移除第二個(gè)?
                     首先我們通過(guò)分析做一個(gè)總結(jié):
                         spring首先從第一個(gè)map中拿a這個(gè)bean
                         拿不到,從第三個(gè)map當(dāng)中拿a這個(gè)對(duì)象
                         拿不到,從第二個(gè)map拿a這個(gè)對(duì)象或者工廠
                         拿到之后放到第三個(gè)map,移除第二個(gè)map里面的表達(dá)式、或者工廠
                     如果對(duì)象需要改變,當(dāng)改變完成之后就把他放到第三個(gè)里面
                     這里的情況是b需要a而進(jìn)行的步驟,試想一下以后如果還有C需要依賴a
                     就不需要重復(fù)第二個(gè)map的工作了,也就是改變對(duì)象的工作了。
                     因?yàn)楦淖兺瓿芍蟮腶對(duì)象已經(jīng)在第三個(gè)map中了。不知道讀者能不能懂筆者的意思
                     如果對(duì)象不需要改變道理是一樣的,也同樣在第三個(gè)map取就是了;
                     至于為什么需要移除第二個(gè)map里面的工廠、或者表達(dá)式就更好理解了
                     他已經(jīng)對(duì)a做完了改變,改變之后的對(duì)象已經(jīng)在第三個(gè)map了,為了方便gc啊
                     下面對(duì)為什么需要改變對(duì)象做分析
                     
                  }
               }
            }
         }
         return singletonObject;
      }
      

      為什么需要改變對(duì)象?那個(gè)表達(dá)式、或者說(shuō)工廠主要干什么事呢? 那個(gè)工廠、或者表達(dá)式主要是調(diào)用了下面這個(gè)方法

      //這個(gè)方法內(nèi)容比較少,但是很復(fù)雜,因?yàn)槭菍?duì)后置處理器的調(diào)用
      //關(guān)于后置處理器筆者其實(shí)要說(shuō)話很多很多
      //現(xiàn)在市面上可見(jiàn)的資料或者書(shū)籍對(duì)后置處理器的說(shuō)法筆者一般都不茍同
      //我在B站上傳過(guò)一個(gè)4個(gè)小時(shí)的視頻,其中對(duì)spring后置處理器做了詳細(xì)的分析
      //也提出了一些自己的理解和主流理解不同的地方,有興趣同學(xué)可以去看看
      //其實(shí)簡(jiǎn)單說(shuō)--這個(gè)方法作用主要是為了來(lái)處理aop的;
      //當(dāng)然還有其他功能,但是一般的讀者最熟悉的就是aop
      //這里我說(shuō)明一下,aop的原理或者流程有很多書(shū)籍說(shuō)到過(guò)
      //但是筆者今天親測(cè)了,現(xiàn)在市面可見(jiàn)的資料和書(shū)籍對(duì)aop的說(shuō)法都不全
      //很多資料提到aop是在spring bean的生命周期里面填充屬性之后的代理周期完成的
      //而這個(gè)代理周期甚至是在執(zhí)行生命周期回調(diào)方法之后的一個(gè)周期
      //那么問(wèn)題來(lái)了?什么叫spring生命周期回調(diào)方法周期呢?
      // 首先spring bean生命周期和spring生命周期回調(diào)方法周期是兩個(gè)概念
      //spring生命周期回調(diào)方法是spring bean生命周期的一部分、或者說(shuō)一個(gè)周期
      //簡(jiǎn)單理解就是spring bean的生命的某個(gè)過(guò)程會(huì)去執(zhí)行spring的生命周期的回調(diào)方法
      //比如你在某個(gè)bean的方法上面寫(xiě)一個(gè)加@PostConstruct的方法(一般稱bean初始化方法)
      //那么這個(gè)方法會(huì)在spring實(shí)例化一個(gè)對(duì)象之后,填充屬性之后執(zhí)行這個(gè)加注解的方法
      //我這里叫做spring 生命周期回調(diào)方法的生命周期,不是我胡說(shuō),有官方文檔可以參考的
      //在執(zhí)行完spring生命周期回調(diào)方法的生命周期之后才會(huì)執(zhí)行代理生命周期
      //在代理這個(gè)生命周期當(dāng)中如果有需要會(huì)完成aop的功能
      //以上是現(xiàn)在主流的說(shuō)法,也是一般書(shū)籍或者“某些大師”的說(shuō)法
      //但是在循環(huán)引用的時(shí)候就不一樣了,循環(huán)引用的情況下這個(gè)周期這里就完成了aop的代理
      //這個(gè)周期嚴(yán)格意義上是在填充屬性之前(填充屬性也是一個(gè)生命周期階段)
      //填充屬性的周期甚至在生命周期回調(diào)方法之前,更在代理這個(gè)周期之前了
      //簡(jiǎn)單來(lái)說(shuō)主流說(shuō)法代理的生命周期比如在第8個(gè)周期或者第八步吧
      //但是筆者這里得出的結(jié)論,如果一個(gè)bean是循環(huán)引用的則代理的周期可能在第3步就完成了
      //那么為什么需要在第三步就完成呢?
      //試想一下A、B兩個(gè)類,現(xiàn)在對(duì)A類做aop處理,也就是需要對(duì)A代理
      不考慮循環(huán)引用 spring 先實(shí)例化A,然后走生命周期確實(shí)在第8個(gè)周期完成的代理
      關(guān)于這個(gè)結(jié)論可以去看b站我講的spring aop源碼分析
      但是如果是循環(huán)依賴就會(huì)有問(wèn)題
      比如spring 實(shí)例化A 然后發(fā)現(xiàn)需要注入B這個(gè)時(shí)候A還沒(méi)有走到8步
      還沒(méi)有完成代理,發(fā)覺(jué)需要注入B,便去創(chuàng)建B,創(chuàng)建B的時(shí)候
      發(fā)覺(jué)需要注入A,于是創(chuàng)建A,創(chuàng)建的過(guò)程中通過(guò)getSingleton
      得到了a對(duì)象,注意是對(duì)象,一個(gè)沒(méi)有完成代理的對(duì)象
      然后把這個(gè)a注入給B?這樣做合適嗎?注入的a根本沒(méi)有aop功能;顯然不合適
      因?yàn)閎中注入的a需要是一個(gè)代理對(duì)象
      而這個(gè)時(shí)候a存在第二個(gè)map中;不是一個(gè)代理對(duì)象;
      于是我在第二個(gè)map中就不能單純的存一個(gè)對(duì)象,需要存一個(gè)工廠
      這個(gè)工廠在特殊的時(shí)候需要對(duì)a對(duì)象做改變,比如這里說(shuō)的代理(需要aop功能的情況)
      這也是三個(gè)map存在的必要性,不知道讀者能不能get到點(diǎn)
      
      
      
      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;
      }
      

      總結(jié)關(guān)于循環(huán)引用,如何回答面試:
      首先spring在單例的情況下是默認(rèn)支持循環(huán)引用的(當(dāng)然原形也有辦法,今天先不討論);在不做任何配置的情況下,兩個(gè)bean相互依賴是能初始化成功的;spring源碼中在創(chuàng)建bean的時(shí)候先創(chuàng)建這個(gè)bean的對(duì)象,創(chuàng)建對(duì)象完成之后通過(guò)判斷容器對(duì)象的allowCircularReferences屬性決定是否允許緩存這個(gè)臨時(shí)對(duì)象,如果能被緩存成功則通過(guò)緩存提前暴露這個(gè)臨時(shí)對(duì)象來(lái)完成循環(huán)依賴;而這個(gè)屬性默認(rèn)為true,所以說(shuō)spring默認(rèn)支持循環(huán)依賴的,但是這個(gè)屬性spring提供了api讓程序員來(lái)修改,所以spring也提供了關(guān)閉循環(huán)引用的功能;再就是spring完成這個(gè)臨時(shí)對(duì)象的生命周期的過(guò)程中當(dāng)執(zhí)行到注入屬性或者自動(dòng)裝配的周期時(shí)候會(huì)通過(guò)getSingleton方法去得到需要注入的b對(duì)象;而b對(duì)象這個(gè)時(shí)候肯定不存在故而會(huì)創(chuàng)建b對(duì)象創(chuàng)建b對(duì)象成功后繼續(xù)b對(duì)象的生命周期,當(dāng)執(zhí)行到b對(duì)象的自動(dòng)注入周期時(shí)候會(huì)要求注入a對(duì)象;調(diào)用getSingleton;從map緩存中得到a的臨時(shí)對(duì)象(因?yàn)檫@個(gè)時(shí)候a在set集合中;這里可以展開(kāi)講),而且獲取的時(shí)候也會(huì)判斷是否允許循環(huán)引用,但是判斷的這個(gè)值是通過(guò)參數(shù)傳進(jìn)來(lái)的,也就是spring內(nèi)部調(diào)用的,spring源碼當(dāng)中寫(xiě)死了為true,故而如果需要擴(kuò)展spring、或者對(duì)spring二次開(kāi)發(fā)的的時(shí)候程序員可以自定義這個(gè)值來(lái)實(shí)現(xiàn)自己的功能;不管放到緩存還是從緩存中取出這個(gè)臨時(shí)都需要判斷;而這兩次判斷spring源碼當(dāng)中都是默認(rèn)為true;這里也能再次說(shuō)明spring默認(rèn)是支持循環(huán)引用的;

      然后面試中可以在說(shuō)說(shuō)兩次調(diào)用getSingleton的意義,正在創(chuàng)建的那個(gè)set集合有什么用;最后在說(shuō)說(shuō)你在看spring循環(huán)引用的時(shí)候得出的aop實(shí)例化過(guò)程的新發(fā)現(xiàn);就比較完美了

      如果文字看不懂可以關(guān)注這個(gè),我會(huì)通過(guò)視頻來(lái)講解
      https://ke.qq.com/course/447566?from=800004101#term_id=100535028

      魯班-子路

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多