咱們在以前的文章中,對spring加載bean的流程作了詳細的講解,咱們知道要將xml中的各個節點解析成真正的bean要通過下面的主要過程:java
一、將xml中的信息解析成BeanDefinition,這其中,XmlBeanDefinitionReader專門負責去讀取xml,而且將xml中的信息解析成BeanDefinition放到DefaultListableBeanFactory中。git
二、BeanFactoryPostProcessor去根據本身的須要修改BeanFactory中已經加載好的BeanDefinitiongithub
三、拿到全部的beanName,一個一個的去對單例調用getBean方法去初始化,這個過程分爲了如下步驟:面試
話說其實我是不怎麼願意講面試題的,由於我認爲你把源碼看懂以後根本就不須要看這樣的東西,可是大多數讀者貌似都有這樣的需求,因此也就沒辦法,說說最多見的一些面試題spring
順便求一波贊,祝點讚的人面試一飛沖天😄~ 編程
Spring怎麼解決循環依賴: 循環依賴主要是經過三層緩存來解決的,三層緩存並非官方概念,固然我也不知道是誰提出來的這個概念,就姑且這麼叫吧。這三層緩存在源碼中分別是singletonObjects,earlySingletonObjects,以及singletonFactories這三個map。其中singletonObjects是用來保存建立好的成品對象,earlySingletonObjects是用來保存提早曝光出來的對象,singletonFactories是用來保存獲取半成品對象的ObjectFactory的。它們是怎麼配合起來解決循環依賴的呢?咱們來看個最簡單的例子:緩存
有兩個類A和B,A中有類型爲B的成員屬性,B中又有類型爲A的成員屬性,注意不能是prototype,也不能是構造器依賴。當建立了一個不完整的A對象時候(其實也就是隻調用了A的構造方法而沒有進行屬性填充),這時候會把這個「不完整」的A對象包裝成ObjectFactory後放到singletonFactories中,再去作屬性填充的動做,而後就在屬性填充的時候發現了須要初始化B,就跑去初始化B去了,而後也是先建立了一個不完整的B而且包裝成ObjectFactory放到了singletonFactories後去填充屬性,這時候發現須要一個A,而後又去初始化A,可是此時singletonFactories裏面的話已經有個不完整的A的ObjectFactory了,這時候就能夠經過這個singletonFactories來獲取到半成品的A的ObjectFactory,再經過A的ObjectFactory獲取到半成品A,注意這裏還會把這個半成品A的ObjectFactory從singletonFactories移除,而後還會把半成品A放到earlySingletonObjects中去,拿到半成品A後去填充B,B建立完了以後再用建立完的B填充A,這樣A和B的建立過程就完成了springboot
爲何須要把半成品A放到earlySingletonObjects中去呢?你能夠試着結合那部分的源碼想一下A依賴B,B依賴C,C依賴D,D又依賴A、B、C的這種複雜循環依賴場景你就會明白了。另外earlySingletonObjects的設計並不只僅是爲了解決循環依賴,它是還有別的做用的(代理相關的),因此不要僅僅只是背面試題。我如今再就問你一個問題,Spring是怎樣判斷你的這兩個Class是否是循環依賴的?估計不少只是背題的人就懵了,因此只背題而根本都不看相關源碼的話,面試官老是能夠花式吊打你的,不信你到我面前來試試😈 框架
爲了把這個問題說的更清楚一些,我不顧讓圖變醜的巨大危險,給圖裏的步驟上面標上了表示步驟的數字🤦,微服務
咱們一步一步來看:
第1步,建立一個"不完整"的bean對象,細節在第五篇的creatBeanInstance方法中,這是建立bean必須通過的過程(除過代理);
第2步填充屬性也是必須通過的,哪怕你沒有屬性,這一步也是要走的;
第3步這個,是先檢查你的bean是否是實現了Aware接口,沒有實現Aware那就直接跳過了,若是實現了Aware,還要檢查是哪一個Aware,而後纔會給你設置某個Aware,這裏會檢查三個Aware,分別是BeanNameAware、BeanClassLoaderAware、BeanFactoryAware這三個Aware,注意確定是沒有ApplicationContextAware的,網上說有這個Aware的怕是本身都根本沒看過源碼的;
第4步這個是BeanPostProcessor的前置處理,是必須通過的;
第5步和第6步,都是先要檢查,而後知足條件才調用,沒有的話就跳過了;
第7步這個是BeanPostProcessor的後置處理,也是必須通過的;
第8步是你這個bean必須是個DisposableBean或者實現了java的AutoCloseable接口,或者你得實現DestructionAwareBeanPostProcessor這個接口,纔會走這步,這時候會把你知足條件的bean加到disposableBeans這個map中方便後續調用(和三層緩存在一個類中);
第9步對應的是咱們在業務中的使用;
第10和第11步是對應銷燬bean,這個一般是由於AbstrctApplicationContext的close方法被調用,這時候會調用以前存在disposableBeans中的全部bean的相關銷燬的方法,也是屬於不必定會走的方法。
爲何我把圖上的文字「Bean的實例化過程」用紅框圈出來了呢?由於很明顯,這個圖不只僅包含建立了,而是還有銷燬過程,所以我以爲這個圖更應該叫作bean的生命週期而不是Bean的實例化過程纔對(我的觀點)~
到這裏,整個正篇部分就完了,後邊還有一些擴展篇沒有寫完。或許你到這裏以爲spring ioc的代碼很牛,但其實真正牛的是ioc的這種思想,它真正意義上解決了面向對象的痛點。不少人都很認同spring爲java續命了十幾年,這種說法我必定程度上是認同的,如今spring系列的東西爲咱們的開發生產帶來了太多的便利,固然也淘汰了一大批人,不少人只會crud的逐漸適應不了這種變化,也有不少人抱怨變化太快,可是若是你一直也只是會用別人封裝的東西的話那其實說真的,不淘汰你淘汰誰?
話又說回來,Spring解決了面向對象編程的痛點,那又有什麼缺點呢?咱們如今作微服務的小夥伴確定都有這樣的體驗,就是一個springboot應用,明明咱們業務代碼在裏面沒有多少,可是這個應用真正跑起來都很很費內存,這個就和spring應用在運行期間有自動裝載了不少的bean有着千絲萬縷的關係,這一點其實不太符合微服務的這個味道。
至於爲何要讀源碼,我想看到我說這些內心話的這塊的人,咱們是有一個共同的目標,那就是但願本身能成爲一個比別人更好一些的工程師。我本身是的目標即是要本身作的可以比別人更好。Ioc這部分源碼看完了以後,以爲看不少框架層面報的錯都變簡單了不少,更重要的是去看好多框架和Spring整合的源碼這裏是真的變得很容易,這並非我在裝逼,而是本身真真實實的收穫和提升。
或許你雖然看到了這裏可是前面的文章卻都還看的不太明白,這其實很正常,我仍是建議你能從我第一篇給出來的github上面把個人代碼拉下來,進去對着個人註釋跟一跟,研究源碼,歷來不可能只是看看別人的文章就能明白那裏面的東西,那是必須一遍遍的看,一遍遍的debug。也有不少讀者頗有野心,老是想在面試的時候反手把面試官按在地上摩擦一下證實證實本身,可是那絕對不是說是你背多少題就能作到的,要想經得起考驗,確定是要把內功練好的。想要變得比別人強這點恆心仍是須要有的,我看源碼看的頭昏眼花,可是最後都堅持下來了。若是有什麼問題實在不明白,也能夠和我來溝通,我若是有時間會給你講,個人郵箱是554013882@qq.com,文章有什麼問題,也能夠發到這裏來。