SpringBoot?Bean實(shí)例化流程解析
前置工作
新建一個(gè)RestService,代碼如下
package geek.springboot.application.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
/**
* Rest Service
*
* @author Bruse
*/
@Slf4j
@Service
public class RestService {
@PostConstruct
public void init() {
log.info("RestService init....");
}
}finishBeanFactoryInitialization
來(lái)到 AbstractApplicationContext 的 refresh() 方法,在該方法中調(diào)用了 finishBeanFactoryInitialization() 方法

判斷是否存在conversionService
首先判斷當(dāng)前IOC容器中是否存在 conversionService ,有的話將其設(shè)置到 BeanFactory 中

判斷是否已有BeanFactoryPostProcessor
接下來(lái)判斷當(dāng)前 BeanFactory 中是否存在 BeanFactoryPostProcessor ,沒(méi)有的話注冊(cè)一個(gè)默認(rèn)的實(shí)現(xiàn)

初始化LoadTimeWeaverAware
接著查詢當(dāng)前IOC容器中是否存在 LoadTimeWeaverAware 的實(shí)現(xiàn),有的話則進(jìn)行初始化。該類(lèi)是使用AOP時(shí)做織入的一個(gè)工具類(lèi),一般情況下開(kāi)發(fā)不會(huì)使用到它,所以這里其實(shí)并不會(huì)執(zhí)行到循環(huán)體中的 getBean()

停止使用TempClassLoader
接下來(lái)將 BeanFactory 的 tempClassLoader 屬性設(shè)置為null

調(diào)用freezeConfiguration()
接下來(lái)調(diào)用 freezeConfiguration() 方法,該方法主要是做一個(gè) 凍結(jié) 聲明,即聲明在此期間無(wú)法再向 BeanFactory 注冊(cè)新的Bean定義


調(diào)用preInstantiateSingletons()
最后也是最關(guān)鍵的,調(diào)用 preInstantiateSingletons() 方法進(jìn)行Bean的實(shí)例化

實(shí)例化Bean
最終其實(shí)會(huì)調(diào)用到 DefaultListableBeanFactor 的 preInstantiateSingletons() 方法。
首先會(huì)獲取當(dāng)前所有Bean定義的名稱,并進(jìn)行遍歷

Tips:除了之前定義的service,controller,config...也包含了Spring內(nèi)置的一些Bean
接著根據(jù)名稱獲取相關(guān)的 BeanDefinition ,也就是Bean的定義,它包括了Bean的一些元信息,比如是否單例,是否延遲初始化,該Bean依賴項(xiàng)等。

Tips:這里為了避免混淆視聽(tīng),我事先已經(jīng)在debug斷點(diǎn)處加上了觸發(fā)條件,只有beanName是restService時(shí),斷點(diǎn)才生效。

可以看到Spring會(huì)先根據(jù) BeanDefinition 判斷出當(dāng)前類(lèi)是否 抽象類(lèi) ,是否 單例 ,是否 延遲加載 。只有當(dāng)當(dāng)前 BeanDefinition 滿足既不是 抽象類(lèi) ,也不 延遲加載 的 單例 時(shí),才會(huì)進(jìn)行操作。
接著還會(huì)判斷當(dāng)前 Bean 是否實(shí)現(xiàn)了 FactoryBean 的接口,是的話則還要對(duì) Bean 做一些處理。
因?yàn)橹皠?chuàng)建的 RestService 沒(méi)有實(shí)現(xiàn) FactoryBean 接口,所以直接調(diào)用 getBean 方法

doGetBean
接著走到 AbstractBeanFactory 的 doGetBean() 方法,該方法主要作用就是返回一個(gè)指定的Bean實(shí)例

transformedBeanName
首先是對(duì) Bean 的名稱做一個(gè)處理,其中包含了若 BeanName 中包含了 FACTORY_BEAN_PREFIX 的話,則將其從 BeanName 中刪除的邏輯

同時(shí)如果有設(shè)置 別名 的話,也會(huì)獲取真正的 BeanName 再返回

getSingleton
接著進(jìn)入 DefaultSingletonBeanRegistry 的 getSingleton 方法,該方法主要作用是 返回給定名稱注冊(cè)的單例對(duì)象

雖然這里邏輯很長(zhǎng),還用到了 雙檢鎖 機(jī)制,但是其實(shí)從 singletonObjects 中檢查是否有對(duì)應(yīng) beanName 的 Bean 存在時(shí),因?yàn)槭堑谝淮蝿?chuàng)建,所以 singletonObjects 中并不存在相關(guān)的 Bean ,直接沒(méi)進(jìn) if 方法體,就返回 null 了

isPrototypeCurrentlyInCreation

接著執(zhí)行 AbstractBeanFactory 的 isPrototypeCurrentlyInCreation 方法,該方法主要是檢查該 beanName 相關(guān)的 Bean 是否在當(dāng)前線程創(chuàng)建中,因?yàn)槲覀冞@里還沒(méi)有進(jìn)行創(chuàng)建,所以這里方法返回false。
獲取BeanFactory

接著嘗試獲取父類(lèi) BeanFactory ,并調(diào)用父類(lèi) BeanFactory 的 getBean 方法獲取 Bean ,但是因?yàn)楫?dāng)前的 beanFactory 已經(jīng)是最頂級(jí)的了,所以直接跳過(guò)大段代碼。
Tips:Spring中BeanFactory跟JVM實(shí)現(xiàn)雙親委派機(jī)制的ClassLoader一樣,也存在子級(jí)父級(jí)關(guān)系
markBeanAsCreated
接著執(zhí)行 markBeanAsCreated 方法,這里也用到了 雙檢鎖 機(jī)制,方法很簡(jiǎn)單,就是將 beanName 添加到 alreadyCreated 當(dāng)中,算是做一個(gè)標(biāo)識(shí),標(biāo)識(shí)當(dāng)前 beanName 對(duì)應(yīng)的 Bean 正在創(chuàng)建當(dāng)中。

getMergedLocalBeanDefinition
接著調(diào)用 getMergedLocalBeanDefinition 方法獲取 BeanDefinition ,并檢查是否是抽象類(lèi),是的話直接拋出異常


檢查是否存在依賴

接著檢查當(dāng)前要實(shí)例化的 Bean 是否和別的Bean存在依賴關(guān)系,是的話得先把所依賴的 Bean 創(chuàng)建好,才能繼續(xù)實(shí)例化當(dāng)前的 Bean 。
因?yàn)?RestService 中沒(méi)有依賴什么別的 Bean ,所以這里略過(guò)一段代碼
根據(jù)作用域創(chuàng)建Bean
接著便是根據(jù)作用域的不同,使用不同方式創(chuàng)建 Bean

getSingleton
這里進(jìn)入 DefaultSingletonBeanRegistry 的 getSingleton 方法

這里首先還是會(huì)檢查當(dāng)前 Bean 是否已初始化,是的話直接返回

createBean
接著調(diào)用 ObjectFactory 的 getObject 方法,因?yàn)閭鲄r(shí)是傳遞了一個(gè) 匿名內(nèi)部類(lèi) ,所以重新回到 AbstractBeanFactory ,可以看到調(diào)用了 createBean 方法

resolveBeanClass
接著來(lái)到 AbstractAutowireCapableBeanFactory 的 createBean 方法,首先會(huì)調(diào)用 AbstractBeanFactory 的 resolveBeanClass 方法對(duì) BeanDefinition 對(duì)應(yīng)的 Class 做一個(gè)解析,這里因?yàn)橹耙呀?jīng)過(guò)了,所以直接返回。


resolveBeforeInstantiation

接著來(lái)到 resolveBeforeInstantiation 方法,可以看到如果它返回的 Bean 不為空,那么將直接返回,意味著 Bean 實(shí)例化完成。
接著深入查看具體實(shí)現(xiàn)細(xì)節(jié),可以看到會(huì)判斷當(dāng)前IOC容器是否存在 InstantiationAwareBeanPostProcessor 接口的實(shí)現(xiàn)

如果存在 InstantiationAwareBeanPostProcessor 接口實(shí)現(xiàn),則會(huì)調(diào)用其 postProcessBeforeInstantiation 方法,如果該方法返回值不為空,那么直接返回,并且調(diào)用 postProcessAfterInitialization 方法再對(duì)返回值做一些處理


因?yàn)楫?dāng)前項(xiàng)目中并沒(méi)有存在 InstantiationAwareBeanPostProcessor 接口實(shí)現(xiàn),所以直接返回的是 null
doCreateBean
所以初始化 Bean 的重任還是交給了 doCreateBean 方法

首先判斷當(dāng)前 Bean 是否單例,是的話將其從 factoryBeanInstanceCache 中移除

createBeanInstance
接著進(jìn)入 createBeanInstance 方法,首先調(diào)用 getInstanceSupplier 方法判斷當(dāng)前 BeanDefinition 是否從其它配置加載的,然后調(diào)用 getFactoryMethodName 方法判斷當(dāng)前 BeanDefinition 是否存在工廠方法, RestService 兩個(gè)條件都不滿足,所以會(huì)一路執(zhí)行到后續(xù)代碼。

determineConstructorsFromBeanPostProcessors
接著執(zhí)行到 determineConstructorsFromBeanPostProcessors 方法,該方法主要是 確定使用哪個(gè)構(gòu)造器來(lái)初始化Bean

可以看到內(nèi)部實(shí)現(xiàn)其實(shí)是依靠調(diào)用 SmartInstantiationAwareBeanPostProcessor 的 determineCandidateConstructors 方法來(lái)進(jìn)行確定的

但其實(shí)最后返回的是 null

instantiateBean
最后來(lái)到 instantiateBean 方法,由注釋也可以看出,該方法就是在 Bean 無(wú)需做特殊處理,調(diào)用默認(rèn)無(wú)參構(gòu)造函數(shù)即可初始化時(shí)調(diào)用的。


首先調(diào)用 getInstantiationStrategy 方法獲取 實(shí)例化策略 ,可以看到默認(rèn) 實(shí)例化策略 是 CglibSubclassingInstantiationStrategy

instantiate
接著調(diào)用 instantiate 方法,在該方法中利用反射機(jī)制獲取 類(lèi)默認(rèn)構(gòu)造函數(shù)

BeanUtils.instantiateClass
最后調(diào)用 BeanUtils 的 instantiateClass 方法進(jìn)行構(gòu)建,可以看出其實(shí)該方法內(nèi)部就是用了Java的 反射機(jī)制 進(jìn)行類(lèi)的實(shí)例構(gòu)建

BeanWrapper
Bean 實(shí)例成功創(chuàng)建后,會(huì)創(chuàng)建 BeanWrapper 實(shí)例來(lái)對(duì) Bean 實(shí)例做一個(gè)包裝,并調(diào)用 initBeanWrapper 方法對(duì) BeanWrapper 進(jìn)行初始化操作

可以看到最后返回的不是 BeanInstance ,而是把 BeanInstance 給包裹了一層,返回的 BeanWrapper 。

applyMergedBeanDefinitionPostProcessors
接著調(diào)用 applyMergedBeanDefinitionPostProcessors 方法,該方法本質(zhì)即獲取所有 MergedBeanDefinitionPostProcessor 實(shí)現(xiàn),并逐個(gè)調(diào)用其 postProcessMergedBeanDefinition 方法


populateBean
接著執(zhí)行 populateBean 方法,該方法主要用來(lái)填充當(dāng)前的 BeanInstance

會(huì)獲取當(dāng)前 BeanDefinition 的所有 Property ,并判斷以何種方式進(jìn)行自動(dòng)注入,根據(jù)類(lèi)型?根據(jù)名稱?

還可以看到會(huì)嘗試獲取所有 InstantiationAwareBeanPostProcessor 實(shí)現(xiàn),并調(diào)用其 postProcessProperties 方法

總結(jié)
在Spring實(shí)例化Bean的過(guò)程中, BeanDefinition 幾乎貫穿了整個(gè)流程,而 BeanDefinition 是一個(gè)對(duì)象在Spring中的描述,Spring通過(guò)操作 BeanDefinition 來(lái)完成 Bean 的實(shí)例化和屬性注入,而實(shí)例化的過(guò)程中又使用到了Java中非?;A(chǔ)且重要的—— 反射
以上就是SpringBoot Bean實(shí)例化流程解析的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Bean實(shí)例化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解javaweb中jstl如何循環(huán)List中的Map數(shù)據(jù)
這篇文章主要介紹了詳解javaweb中jstl如何循環(huán)List中的Map數(shù)據(jù)的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家理解掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10
使用Java 壓縮文件打包tar.gz 包的詳細(xì)教程
本文帶領(lǐng)大家學(xué)習(xí)如何使用Java 壓縮文件打包tar.gz 包,主要通過(guò) Apache compress 工具打包,通過(guò)示例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2021-05-05
IDEA?2022最新激活碼注冊(cè)碼超詳細(xì)教程(親測(cè)激活有效)
這篇文章主要介紹了IDEA?2022最新激活碼超詳細(xì)教程(親測(cè)激活至2099年),本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
解決IDEA報(bào)錯(cuò)Caused by: org.springframework.boot.web.se
遇到IDEA啟動(dòng)報(bào)錯(cuò),可嘗試以下方法:打開(kāi)項(xiàng)目設(shè)置(Ctrl+Shift+Alt+S),將JDK版本修改為1.8;或者檢查T(mén)omCat依賴,若有問(wèn)題可嘗試刪除,此外,確保每次拉取項(xiàng)目后,maven地址設(shè)置為本地,并且JDK版本設(shè)置為1.8,以上為個(gè)人解決經(jīng)驗(yàn),希望對(duì)大家有所幫助2024-09-09

