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
來到 AbstractApplicationContext
的 refresh()
方法,在該方法中調(diào)用了 finishBeanFactoryInitialization()
方法
判斷是否存在conversionService
首先判斷當(dāng)前IOC容器中是否存在 conversionService
,有的話將其設(shè)置到 BeanFactory
中
判斷是否已有BeanFactoryPostProcessor
接下來判斷當(dāng)前 BeanFactory
中是否存在 BeanFactoryPostProcessor
,沒有的話注冊一個(gè)默認(rèn)的實(shí)現(xiàn)
初始化LoadTimeWeaverAware
接著查詢當(dāng)前IOC容器中是否存在 LoadTimeWeaverAware
的實(shí)現(xiàn),有的話則進(jìn)行初始化。該類是使用AOP時(shí)做織入的一個(gè)工具類,一般情況下開發(fā)不會(huì)使用到它,所以這里其實(shí)并不會(huì)執(zhí)行到循環(huán)體中的 getBean()
停止使用TempClassLoader
接下來將 BeanFactory
的 tempClassLoader
屬性設(shè)置為null
調(diào)用freezeConfiguration()
接下來調(diào)用 freezeConfiguration()
方法,該方法主要是做一個(gè) 凍結(jié)
聲明,即聲明在此期間無法再向 BeanFactory
注冊新的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:這里為了避免混淆視聽,我事先已經(jīng)在debug斷點(diǎn)處加上了觸發(fā)條件,只有beanName是restService時(shí),斷點(diǎn)才生效。
可以看到Spring會(huì)先根據(jù) BeanDefinition
判斷出當(dāng)前類是否 抽象類
,是否 單例
,是否 延遲加載
。只有當(dāng)當(dāng)前 BeanDefinition
滿足既不是 抽象類
,也不 延遲加載
的 單例
時(shí),才會(huì)進(jìn)行操作。
接著還會(huì)判斷當(dāng)前 Bean
是否實(shí)現(xiàn)了 FactoryBean
的接口,是的話則還要對 Bean
做一些處理。
因?yàn)橹皠?chuàng)建的 RestService
沒有實(shí)現(xiàn) FactoryBean
接口,所以直接調(diào)用 getBean
方法
doGetBean
接著走到 AbstractBeanFactory
的 doGetBean()
方法,該方法主要作用就是返回一個(gè)指定的Bean實(shí)例
transformedBeanName
首先是對 Bean
的名稱做一個(gè)處理,其中包含了若 BeanName
中包含了 FACTORY_BEAN_PREFIX
的話,則將其從 BeanName
中刪除的邏輯
同時(shí)如果有設(shè)置 別名
的話,也會(huì)獲取真正的 BeanName
再返回
getSingleton
接著進(jìn)入 DefaultSingletonBeanRegistry
的 getSingleton
方法,該方法主要作用是 返回給定名稱注冊的單例對象
雖然這里邏輯很長,還用到了 雙檢鎖
機(jī)制,但是其實(shí)從 singletonObjects
中檢查是否有對應(yīng) beanName
的 Bean
存在時(shí),因?yàn)槭堑谝淮蝿?chuàng)建,所以 singletonObjects
中并不存在相關(guān)的 Bean
,直接沒進(jìn) if
方法體,就返回 null
了
isPrototypeCurrentlyInCreation
接著執(zhí)行 AbstractBeanFactory
的 isPrototypeCurrentlyInCreation
方法,該方法主要是檢查該 beanName
相關(guān)的 Bean
是否在當(dāng)前線程創(chuàng)建中,因?yàn)槲覀冞@里還沒有進(jìn)行創(chuàng)建,所以這里方法返回false。
獲取BeanFactory
接著嘗試獲取父類 BeanFactory
,并調(diào)用父類 BeanFactory
的 getBean
方法獲取 Bean
,但是因?yàn)楫?dāng)前的 beanFactory
已經(jīng)是最頂級(jí)的了,所以直接跳過大段代碼。
Tips:Spring中BeanFactory跟JVM實(shí)現(xiàn)雙親委派機(jī)制的ClassLoader一樣,也存在子級(jí)父級(jí)關(guān)系
markBeanAsCreated
接著執(zhí)行 markBeanAsCreated
方法,這里也用到了 雙檢鎖
機(jī)制,方法很簡單,就是將 beanName
添加到 alreadyCreated
當(dāng)中,算是做一個(gè)標(biāo)識(shí),標(biāo)識(shí)當(dāng)前 beanName
對應(yīng)的 Bean
正在創(chuàng)建當(dāng)中。
getMergedLocalBeanDefinition
接著調(diào)用 getMergedLocalBeanDefinition
方法獲取 BeanDefinition
,并檢查是否是抽象類,是的話直接拋出異常
檢查是否存在依賴
接著檢查當(dāng)前要實(shí)例化的 Bean
是否和別的Bean存在依賴關(guān)系,是的話得先把所依賴的 Bean
創(chuàng)建好,才能繼續(xù)實(shí)例化當(dāng)前的 Bean
。
因?yàn)?RestService
中沒有依賴什么別的 Bean
,所以這里略過一段代碼
根據(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)部類
,所以重新回到 AbstractBeanFactory
,可以看到調(diào)用了 createBean
方法
resolveBeanClass
接著來到 AbstractAutowireCapableBeanFactory
的 createBean
方法,首先會(huì)調(diào)用 AbstractBeanFactory
的 resolveBeanClass
方法對 BeanDefinition
對應(yīng)的 Class
做一個(gè)解析,這里因?yàn)橹耙呀?jīng)過了,所以直接返回。
resolveBeforeInstantiation
接著來到 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
方法再對返回值做一些處理
因?yàn)楫?dāng)前項(xiàng)目中并沒有存在 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)造器來初始化Bean
可以看到內(nèi)部實(shí)現(xiàn)其實(shí)是依靠調(diào)用 SmartInstantiationAwareBeanPostProcessor
的 determineCandidateConstructors
方法來進(jìn)行確定的
但其實(shí)最后返回的是 null
instantiateBean
最后來到 instantiateBean
方法,由注釋也可以看出,該方法就是在 Bean
無需做特殊處理,調(diào)用默認(rèn)無參構(gòu)造函數(shù)即可初始化時(shí)調(diào)用的。
首先調(diào)用 getInstantiationStrategy
方法獲取 實(shí)例化策略
,可以看到默認(rèn) 實(shí)例化策略
是 CglibSubclassingInstantiationStrategy
instantiate
接著調(diào)用 instantiate
方法,在該方法中利用反射機(jī)制獲取 類默認(rèn)構(gòu)造函數(shù)
BeanUtils.instantiateClass
最后調(diào)用 BeanUtils
的 instantiateClass
方法進(jìn)行構(gòu)建,可以看出其實(shí)該方法內(nèi)部就是用了Java的 反射機(jī)制
進(jìn)行類的實(shí)例構(gòu)建
BeanWrapper
Bean
實(shí)例成功創(chuàng)建后,會(huì)創(chuàng)建 BeanWrapper
實(shí)例來對 Bean
實(shí)例做一個(gè)包裝,并調(diào)用 initBeanWrapper
方法對 BeanWrapper
進(jìn)行初始化操作
可以看到最后返回的不是 BeanInstance
,而是把 BeanInstance
給包裹了一層,返回的 BeanWrapper
。
applyMergedBeanDefinitionPostProcessors
接著調(diào)用 applyMergedBeanDefinitionPostProcessors
方法,該方法本質(zhì)即獲取所有 MergedBeanDefinitionPostProcessor
實(shí)現(xiàn),并逐個(gè)調(diào)用其 postProcessMergedBeanDefinition
方法
populateBean
接著執(zhí)行 populateBean
方法,該方法主要用來填充當(dāng)前的 BeanInstance
會(huì)獲取當(dāng)前 BeanDefinition
的所有 Property
,并判斷以何種方式進(jìn)行自動(dòng)注入,根據(jù)類型?根據(jù)名稱?
還可以看到會(huì)嘗試獲取所有 InstantiationAwareBeanPostProcessor
實(shí)現(xiàn),并調(diào)用其 postProcessProperties
方法
總結(jié)
在Spring實(shí)例化Bean的過程中, BeanDefinition
幾乎貫穿了整個(gè)流程,而 BeanDefinition
是一個(gè)對象在Spring中的描述,Spring通過操作 BeanDefinition
來完成 Bean
的實(shí)例化和屬性注入,而實(shí)例化的過程中又使用到了Java中非?;A(chǔ)且重要的—— 反射
以上就是SpringBoot Bean實(shí)例化流程解析的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Bean實(shí)例化的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解析Java編程中對于包結(jié)構(gòu)的命名和訪問
這篇文章主要介紹了Java編程中對于包結(jié)構(gòu)的命名和訪問,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-12-12SpringMVC集成Web與MVC執(zhí)行流程和數(shù)據(jù)響應(yīng)及交互相關(guān)介紹全面總結(jié)
Spring MVC 是 Spring 提供的一個(gè)基于 MVC 設(shè)計(jì)模式的輕量級(jí) Web 開發(fā)框架,本質(zhì)上相當(dāng)于 Servlet,Spring MVC 角色劃分清晰,分工明細(xì),這篇文章主要介紹了SpringMVC集成Web與MVC執(zhí)行流程和數(shù)據(jù)響應(yīng)及交互2022-10-10Java 實(shí)戰(zhàn)項(xiàng)目錘煉之仿天貓網(wǎng)上商城的實(shí)現(xiàn)流程
讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+jsp+servlet+mysql+ajax實(shí)現(xiàn)一個(gè)仿天貓網(wǎng)上商城項(xiàng)目,大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11關(guān)于JSON.toJSONString()和Gson.toJson()方法的比較
本文介紹了兩種將Java對象轉(zhuǎn)換為JSON字符串的方法:阿里的`JSON.toJSONString()`和谷歌的`Gson.toJson()`,通過一個(gè)示例,展示了當(dāng)使用繼承關(guān)系且子類覆蓋父類字段時(shí),`Gson`會(huì)報(bào)錯(cuò),而`JSON`可以正常運(yùn)行,作者建議在處理JSON相關(guān)操作時(shí)使用阿里的`JSON`類2024-11-11Java實(shí)戰(zhàn)員工績效管理系統(tǒng)的實(shí)現(xiàn)流程
只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+Mysql+Maven+HTML實(shí)現(xiàn)一個(gè)員工績效管理系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2022-01-01JAVA使用Gson解析json數(shù)據(jù)實(shí)例解析
JSON(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式,易于閱讀和編寫,同時(shí)也易于機(jī)器解析和生成。接下來通過本文給大家介紹JAVA使用Gson解析json數(shù)據(jù)實(shí)例解析,需要的朋友參考下吧2016-03-03Java實(shí)現(xiàn)解壓zip和rar包的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)解壓zip和rar包,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01java正則表達(dá)式應(yīng)用的實(shí)例代碼
java正則的實(shí)例應(yīng)用分析,大家從下面的代碼中,就能知道java正則的應(yīng)用與寫法2008-10-10Mybatis-Plus集成Sharding-JDBC與Flyway實(shí)現(xiàn)多租戶分庫分表實(shí)戰(zhàn)
這篇文章主要為大家介紹了Mybatis-Plus集成Sharding-JDBC與Flyway實(shí)現(xiàn)多租戶分庫分表實(shí)戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11