五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

阿里P8級(jí)別的spring源碼關(guān)于循環(huán)引用的筆記

2019-10-18 17:50 作者:P8架構(gòu)師諸葛  | 我要投稿

最近因?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ō)你寫了個(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)依賴沒什么很大的關(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的書寫者肯定知道這個(gè)bean這個(gè)時(shí)候沒有創(chuàng)建?為什么需要get一次呢?

? ? * 關(guān)于這個(gè)問(wèn)題其實(shí)原因比較復(fù)雜,需要讀者對(duì)spring源碼設(shè)計(jì)比較精通

? ? * 筆者不準(zhǔn)備來(lái)針對(duì)這個(gè)原因大書特書,稍微解釋一下吧

? ? * 我們可以分析doGetBean這個(gè)方法,顧名思義其實(shí)是用來(lái)獲取bean的

? ? * 為什么創(chuàng)建bean會(huì)調(diào)用這個(gè)doGetBean方法呢?難道是因?yàn)閟pring作者疏忽,獲取亂起名字

? ? * 顯然不是,spring的源碼以其書寫優(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è)類如果沒有創(chuàng)建,則會(huì)調(diào)用createBean來(lái)創(chuàng)建這個(gè)bean

? ? * 在創(chuàng)建這個(gè)被引用的bean的過(guò)程中會(huì)判斷這個(gè)bean的對(duì)象有沒有實(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)注意,筆者下文中如果寫到bean和寫到對(duì)象不是隨意寫的

? ? * 是和這里的解釋有關(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)在寫注釋的這個(gè)getSingleton(beanName)

? ? * 這個(gè)時(shí)候get出來(lái)肯定為空?為什么是空呢?我寫這么多注釋就是為了解釋這個(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)在寫的注釋給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è)類沒有創(chuàng)建,然后調(diào)用第二次getSingleton

? ? * 在第二次getSingleton里面記錄了一下自己已經(jīng)開始實(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,有些博客或者書籍人也叫做三級(jí)緩存

? ? * 為什么需要三個(gè)map呢?先來(lái)了解這三個(gè)map到底都緩存了什么

? ? * 第一個(gè)map singletonObjects 存放的單例的bean

? ? * 第二個(gè)map singletonFactories 存放的臨時(shí)對(duì)象(沒有完整springBean生命周期的對(duì)象)

? ? * 第三個(gè)map earlySingletonObjects 存放的臨時(shí)對(duì)象(沒有完整springBean生命周期的對(duì)象)

? ? * 筆者為了讓大家不懵逼這里吧第二個(gè)和第三個(gè)map功能寫成了一模一樣

? ? * 其實(shí)第二個(gè)和第三個(gè)map會(huì)有不一樣的地方,但這里不方便展開講,下文會(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ā)覺a依賴了一個(gè)B類

? ? * 所以spring就會(huì)去判斷這個(gè)B類到底有沒有bean在容器當(dāng)中

? ? * 這里的判斷就是從第一個(gè)map即單例池當(dāng)中去拿一個(gè)bean

? ? * 后面我會(huì)通過(guò)源碼來(lái)證明是從第一個(gè)map中拿一個(gè)bean的

? ? * 假設(shè)沒有,那么spring會(huì)先去調(diào)用createBean創(chuàng)建這個(gè)bean

? ? * 于是又回到和創(chuàng)建A一樣的流程,在創(chuàng)建B的時(shí)候同樣也會(huì)去getBean("B");

? ? * getBean核心也就是筆者現(xiàn)在寫注釋的這個(gè)getSingleton(beanName)方法

? ? * 下面我重申一下:因?yàn)槭侵攸c(diǎn)

? ? * 這個(gè)時(shí)候get出來(lái)肯定為空?為什么是空呢?我寫這么多注釋就是為了解釋這個(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ā)覺b需要依賴A

? ?* 于是就去容器看看A有沒有創(chuàng)建,說(shuō)白了就是從第一個(gè)map當(dāng)中去找a

? ?* 有人會(huì)說(shuō)不上A在前面創(chuàng)建了a嘛?注意那只是個(gè)對(duì)象,不是bean;

? ?* 還不在第一個(gè)map當(dāng)中 對(duì)所以b判定A沒有創(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)中有沒有記錄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還沒有注入

? ?* 當(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ō)法并沒有官方支持

? ?* 是筆者自己的認(rèn)為;各位讀者可以自行給他取名字

? ?* 筆者是因?yàn)榇娣拍切┯涗浀膕et集合的名字叫做singletonsCurrentlyInCreation

? ?* 顧名思義,當(dāng)前正在創(chuàng)建的單例對(duì)象。。。。。

? ?* 還有上文提到的對(duì)象和bean的概念;也沒有官方支持

? ?* 也是筆者為了讓讀者更好的理解spring源碼而提出的個(gè)人概念

? ?* 但是如果你覺得這種方法確實(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)然這里沒有直接返回而是調(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中決定的

? ? ? ? * 這里還沒有執(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ì)開始創(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寫了一行非常重要的注釋

? ?// 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)建,并且是沒有關(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沒有創(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ā)覺需要依賴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)依賴流程全部走完;但是好像沒有說(shuō)到第三個(gè)map,第三個(gè)map到底充當(dāng)了什么角色呢?

這個(gè)知識(shí)點(diǎn)非常的重要,關(guān)于這個(gè)知識(shí)不少書籍和博客都說(shuō)錯(cuò)了,這也是寫這篇文章的意義;筆者說(shuō)每次讀spring源碼都不一樣的收獲,這次最大的收獲便是這里了;我們先來(lái)看一下代碼;

場(chǎng)景是這樣的,spring創(chuàng)建A,記住第一次創(chuàng)建A,過(guò)程中發(fā)覺需要依賴B,于是創(chuàng)建B,創(chuàng)建B的時(shí)候發(fā)覺需要依賴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è)方法

//關(guān)于后置處理器筆者其實(shí)要說(shuō)話很多很多

//現(xiàn)在市面上可見的資料或者書籍對(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的原理或者流程有很多書籍說(shuō)到過(guò)

//但是筆者今天親測(cè)了,現(xiàn)在市面可見的資料和書籍對(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的方法上面寫一個(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ō)法,也是一般書籍或者“某些大師”的說(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還沒有走到8步

還沒有完成代理,發(fā)覺需要注入B,便去創(chuàng)建B,創(chuàng)建B的時(shí)候

發(fā)覺需要注入A,于是創(chuàng)建A,創(chuàng)建的過(guò)程中通過(guò)getSingleton

得到了a對(duì)象,注意是對(duì)象,一個(gè)沒有完成代理的對(duì)象

然后把這個(gè)a注入給B?這樣做合適嗎?注入的a根本沒有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集合中;這里可以展開講),而且獲取的時(shí)候也會(huì)判斷是否允許循環(huán)引用,但是判斷的這個(gè)值是通過(guò)參數(shù)傳進(jìn)來(lái)的,也就是spring內(nèi)部調(diào)用的,spring源碼當(dāng)中寫死了為true,故而如果需要擴(kuò)展spring、或者對(duì)spring二次開發(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);就比較完美了

最后視頻解析在這兒




阿里P8級(jí)別的spring源碼關(guān)于循環(huán)引用的筆記的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
康马县| 肇东市| 麟游县| 马边| 新晃| 宣武区| 临桂县| 浦江县| 昆明市| 旬邑县| 阳谷县| 新化县| 云南省| 隆安县| 海安县| 怀柔区| 若尔盖县| 清水县| 新绛县| 克山县| 云阳县| 天门市| 通许县| 磴口县| 达日县| 漯河市| 大埔区| 大冶市| 武邑县| 大埔县| 宁强县| 邯郸市| 清水河县| 太和县| 右玉县| 荆门市| 上犹县| 宁波市| 娱乐| 阳曲县| 驻马店市|