亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot?Bean實例化流程解析

 更新時間:2023年08月28日 09:58:24   作者:LBruse  
在SpringBoot啟動過程中會執(zhí)行refreshContext()方法,而在其執(zhí)行過程中,又會調(diào)用finishBeanFactoryInitialization()方法,該方法負責了Bean的實例化,那么本文將從源碼跟讀的角度來解析一下具體流程

前置工作

新建一個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() 方法

image.png

判斷是否存在conversionService

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

image.png

判斷是否已有BeanFactoryPostProcessor

接下來判斷當前 BeanFactory 中是否存在 BeanFactoryPostProcessor ,沒有的話注冊一個默認的實現(xiàn)

image.png

初始化LoadTimeWeaverAware

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

image.png

停止使用TempClassLoader

接下來將 BeanFactory tempClassLoader 屬性設(shè)置為null

image.png

調(diào)用freezeConfiguration()

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

image.png

image.png

調(diào)用preInstantiateSingletons()

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

image.png

實例化Bean

最終其實會調(diào)用到 DefaultListableBeanFactor preInstantiateSingletons() 方法。

首先會獲取當前所有Bean定義的名稱,并進行遍歷

image.png

Tips:除了之前定義的service,controller,config...也包含了Spring內(nèi)置的一些Bean

接著根據(jù)名稱獲取相關(guān)的 BeanDefinition ,也就是Bean的定義,它包括了Bean的一些元信息,比如是否單例,是否延遲初始化,該Bean依賴項等。

image.png

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

image.png

可以看到Spring會先根據(jù) BeanDefinition 判斷出當前類是否 抽象類 ,是否 單例 ,是否 延遲加載 。只有當當前 BeanDefinition 滿足既不是 抽象類 ,也不 延遲加載 單例 時,才會進行操作。

接著還會判斷當前 Bean 是否實現(xiàn)了 FactoryBean 的接口,是的話則還要對 Bean 做一些處理。

因為之前創(chuàng)建的 RestService 沒有實現(xiàn) FactoryBean 接口,所以直接調(diào)用 getBean 方法

image.png

doGetBean

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

image.png

transformedBeanName

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

image.png

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

image.png

getSingleton

接著進入 DefaultSingletonBeanRegistry getSingleton 方法,該方法主要作用是 返回給定名稱注冊的單例對象

image.png

雖然這里邏輯很長,還用到了 雙檢鎖 機制,但是其實從 singletonObjects 中檢查是否有對應(yīng) beanName Bean 存在時,因為是第一次創(chuàng)建,所以 singletonObjects 中并不存在相關(guān)的 Bean ,直接沒進 if 方法體,就返回 null

image.png

isPrototypeCurrentlyInCreation

image.png

接著執(zhí)行 AbstractBeanFactory isPrototypeCurrentlyInCreation 方法,該方法主要是檢查該 beanName 相關(guān)的 Bean 是否在當前線程創(chuàng)建中,因為我們這里還沒有進行創(chuàng)建,所以這里方法返回false。

獲取BeanFactory

image.png

接著嘗試獲取父類 BeanFactory ,并調(diào)用父類 BeanFactory getBean 方法獲取 Bean ,但是因為當前的 beanFactory 已經(jīng)是最頂級的了,所以直接跳過大段代碼。

Tips:Spring中BeanFactory跟JVM實現(xiàn)雙親委派機制的ClassLoader一樣,也存在子級父級關(guān)系

markBeanAsCreated

接著執(zhí)行 markBeanAsCreated 方法,這里也用到了 雙檢鎖 機制,方法很簡單,就是將 beanName 添加到 alreadyCreated 當中,算是做一個標識,標識當前 beanName 對應(yīng)的 Bean 正在創(chuàng)建當中。

image.png

getMergedLocalBeanDefinition

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

image.png

image.png

檢查是否存在依賴

image.png

接著檢查當前要實例化的 Bean 是否和別的Bean存在依賴關(guān)系,是的話得先把所依賴的 Bean 創(chuàng)建好,才能繼續(xù)實例化當前的 Bean 。

因為 RestService 中沒有依賴什么別的 Bean ,所以這里略過一段代碼

根據(jù)作用域創(chuàng)建Bean

接著便是根據(jù)作用域的不同,使用不同方式創(chuàng)建 Bean

image.png

getSingleton

這里進入 DefaultSingletonBeanRegistry getSingleton 方法

image.png

這里首先還是會檢查當前 Bean 是否已初始化,是的話直接返回

image.png

createBean

接著調(diào)用 ObjectFactory getObject 方法,因為傳參時是傳遞了一個 匿名內(nèi)部類 ,所以重新回到 AbstractBeanFactory ,可以看到調(diào)用了 createBean 方法

image.png

resolveBeanClass

接著來到 AbstractAutowireCapableBeanFactory createBean 方法,首先會調(diào)用 AbstractBeanFactory resolveBeanClass 方法對 BeanDefinition 對應(yīng)的 Class 做一個解析,這里因為之前已經(jīng)過了,所以直接返回。

image.png

image.png

resolveBeforeInstantiation

image.png

接著來到 resolveBeforeInstantiation 方法,可以看到如果它返回的 Bean 不為空,那么將直接返回,意味著 Bean 實例化完成。

接著深入查看具體實現(xiàn)細節(jié),可以看到會判斷當前IOC容器是否存在 InstantiationAwareBeanPostProcessor 接口的實現(xiàn)

image.png

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

image.png

image.png

因為當前項目中并沒有存在 InstantiationAwareBeanPostProcessor 接口實現(xiàn),所以直接返回的是 null

doCreateBean

所以初始化 Bean 的重任還是交給了 doCreateBean 方法

image.png

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

image.png

createBeanInstance

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

image.png

determineConstructorsFromBeanPostProcessors

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

image.png

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

image.png

但其實最后返回的是 null

image.png

instantiateBean 

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

image.png

image.png

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

image.png

instantiate

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

image.png

BeanUtils.instantiateClass

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

image.png

BeanWrapper

Bean 實例成功創(chuàng)建后,會創(chuàng)建 BeanWrapper 實例來對 Bean 實例做一個包裝,并調(diào)用 initBeanWrapper 方法對 BeanWrapper 進行初始化操作

image.png

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

image.png

applyMergedBeanDefinitionPostProcessors

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

image.png

image.png

populateBean

接著執(zhí)行 populateBean 方法,該方法主要用來填充當前的 BeanInstance

image.png

會獲取當前 BeanDefinition 的所有 Property ,并判斷以何種方式進行自動注入,根據(jù)類型?根據(jù)名稱?

image.png

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

image.png

總結(jié)

在Spring實例化Bean的過程中, BeanDefinition 幾乎貫穿了整個流程,而 BeanDefinition 是一個對象在Spring中的描述,Spring通過操作 BeanDefinition 來完成 Bean 的實例化和屬性注入,而實例化的過程中又使用到了Java中非?;A(chǔ)且重要的—— 反射

以上就是SpringBoot Bean實例化流程解析的詳細內(nèi)容,更多關(guān)于SpringBoot Bean實例化的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論