spring-boot源碼分析之BeanFactory · 貳

前言
BeanFactory是spring boot最重要的核心組件,當(dāng)然也是spring boot非?;A(chǔ)的組件,所以梳理清楚BeanFactory的源碼才是梳理清楚Spring boot源碼的關(guān)鍵。前天,我們分享了beanDefinitionNames和beanDefinitionMap的初始化過程,雖然過程中有涉及到beanFactory的相關(guān)知識(shí)點(diǎn),但是關(guān)于beanFactroy我們還沒有正式地分析過它,關(guān)于它的初始化過程,也是一無所知,為了更系統(tǒng)地了解beanFactory,從今天開始我們開始更系統(tǒng)地分析beanFactory的相關(guān)源碼,下面我們就先來看下BeanFactory的初始化過程。
BeanFactory初始化
今天我們依然是從一張時(shí)序圖開始講起,下面這張時(shí)序圖就是spring boot容器的BeanFactory初始化過程,beanFactory初始化其實(shí)是和容器的初始化同時(shí)完成的,它也是容器初始化過程中的重要一步:

在上面的時(shí)序圖中,最關(guān)鍵的內(nèi)容就是AnnotationConfigServletWebServerApplicationContext的實(shí)例化過程,這里面涉及到java類的初始化流程:創(chuàng)建子類時(shí),必須先調(diào)用父類無參構(gòu)造方法,所以AnnotationConfigServletWebServerApplicationContext是在所有父類實(shí)例化完成后,才完成它自己的實(shí)例化過程的。下面我們就來看AnnotationConfigServletWebServerApplicationContext的初始化流程。
createApplicationContext
在debug的過程中,我發(fā)現(xiàn) BeanFactory在容器被創(chuàng)建后就已經(jīng)被初始化,這也就是說BeanFactory其實(shí)是在spring boot容器創(chuàng)建過程中被初始化的,所以我們今天主要就是研究容器創(chuàng)建過程,也就是createApplicationContext()方法:

關(guān)于createApplicationContext這個(gè)方法,我們前面已經(jīng)展示過了,它的作用就是通過反射創(chuàng)建容器實(shí)例:

AnnotationConfigServletWebServerApplicationContext實(shí)例化
通過跟蹤代碼,最終可以確認(rèn),調(diào)用的是AnnotationConfigServletWebServerApplicationContext無參構(gòu)造方法:

所以下面就是對(duì)AnnotationConfigServletWebServerApplicationContext的實(shí)例化,由于容器這塊繼承關(guān)系比較復(fù)雜,所以實(shí)例化順序也比較復(fù)雜。
容器實(shí)例化
雖然各位小伙伴可能很清楚java對(duì)象實(shí)例化過程,但是我覺得還是有必要再補(bǔ)充說明下。在有繼承關(guān)系的java對(duì)象實(shí)例化過程中,如果當(dāng)前類繼承了父類,在實(shí)例化當(dāng)前類時(shí),先要調(diào)用父類的無參構(gòu)造方法(就算不指定,也會(huì)隱式調(diào)用)。所以,在這里初始AnnotationConfigServletWebServerApplicationContext時(shí),會(huì)先調(diào)用它的父類無參構(gòu)造方法,下面是AnnotationConfigServletWebServerApplicationContext的繼承關(guān)系,看起來確實(shí)很復(fù)雜:

在跟蹤代碼的過程中,最終我確認(rèn)BeanFactory是在GenericApplicationContext的無參構(gòu)造方法中完成初始化的,也就是AnnotationConfigServletWebServerApplicationContext父類的父類的父類:

所以初始化的過程就是,AnnotationConfigServletWebServerApplicationContext的無參構(gòu)造方法中先調(diào)用ServletWebServerApplicationContext的無參構(gòu)造方法,ServletWebServerApplicationContext的無參構(gòu)造方法中先調(diào)用GenericWebApplicationContext的無參構(gòu)造方法,GenericWebApplicationContext的無參構(gòu)造方法先調(diào)用GenericApplicationContext的無參構(gòu)造方法(無限套娃)……
知識(shí)擴(kuò)展
后續(xù)的調(diào)用這里就直接省略了,因?yàn)樗麄兒?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">BeanFactory沒有關(guān)系,而且因?yàn)槔^承關(guān)系過于復(fù)雜,所以這里我們要盡可能簡(jiǎn)單。在這里所有的初始化操作中,調(diào)用父類構(gòu)造方法始終是首先被執(zhí)行的,也必須首先被執(zhí)行(首先調(diào)用父類的無參構(gòu)造方法),這也就是為什么我們?cè)趯戭惖挠袇?gòu)造方法的時(shí)候,如果父類沒有無參構(gòu)造方法時(shí),必須顯式調(diào)用父類有參構(gòu)造方法,且必須放在第一行的原因:



總結(jié)
截止到今天,我們已經(jīng)梳理清楚beanFactory的兩塊內(nèi)容,一個(gè)是beanDefinitionNames和beanDefinitionMap,他們都是beanFactory的核心屬性,另一塊就是我們今天的BeanFactory的初始化,下一步應(yīng)該還是會(huì)進(jìn)一步深挖beanFactory的相關(guān)知識(shí)點(diǎn),因?yàn)閺囊婚_始我的想法就是要找到spring boot包掃描和實(shí)例化bean的相關(guān)邏輯,但到目前為止還沒有理清楚這一塊的邏輯和流程,不過我相信很快我們就能完成這個(gè)目標(biāo)了,因?yàn)槲覀兊拿恳徊蕉荚诟拷繕?biāo)……
