国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

這篇具有很好參考價值的文章主要介紹了【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

問題:Spring中是如何初始化單例bean的?

我們都知道Spring解析xml文件描述成BeanDefinition,解析BeanDefinition最后創(chuàng)建Bean將Bean放入單例池中,那么Spring在創(chuàng)建Bean的這個過程都做了什么。

Spring核心方法refresh()中最最重要的一個方法 finishBeanFactoryInitialization() 方法,該方法負(fù)責(zé)初始化所有的單例bean。

finishBeanFactoryInitialization()方法位于refresh()中第11步。

【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

走到這一步的時候,Spring容器中所有的BeanFactory都已經(jīng)實例化完成了,也就是實現(xiàn)BeanFactoryPostProcessor接口的 Bean 都已經(jīng)初始化完成了。剩下的就是初始化singleton beans,在我們的業(yè)務(wù)bean中大多數(shù)都是單例的,finishBeanFactoryInitialization這一步就是去實例化單例的并且沒有設(shè)置懶加載的Bean。

Spring會在finishBeanFactoryInitialization這個方法里面初始化所有的singleton bean

Ok,我們先來看一下finishBeanFactoryInitialization方法內(nèi)部的邏輯。這個方法的核心就在于完成BeanFactory的配置。該階段完成了上下文的實例化,包含所有單例Bean對象已經(jīng)實例化。

【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

核心在于 preInstantiateSingletons() 方法,preInstantiateSingletons方法主要任務(wù)是進(jìn)行初始化,在初始化前同樣是一系列判斷,如,是否是懶加載的,是否是一個factorybean(一個特別的bean,負(fù)責(zé)工廠創(chuàng)建的bean),最后調(diào)用getBean()方法。
【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

注釋中提到的SmartInitializingSingleton接口,是讓bean初始化后做一些操作。
【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程
【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

OK,那么主要的方法還是getBean()方法,getBean()方法的作用就是加載、實例化Bean。方法內(nèi)部調(diào)用了doGetBean(),我們直接看**doGetBean()**方法內(nèi)部。
【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

代碼很多,我們主要看createBean()方法。
【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

我們繼續(xù)往doCreateBean 這個方法里面看。
【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

方法很多,我們主需要關(guān)注三個方法即可。

  • createBeanInstance:實例化,其實也就是調(diào)用對象的構(gòu)造方法實例化對象
  • populateBean:填充屬性,這一步主要是多bean的依賴屬性進(jìn)行填充
  • initializeBean:調(diào)用spring xml中的init 方法。

從上面講述的單例bean初始化步驟我們可以知道,循環(huán)依賴主要發(fā)生在第一、第二步。也就是構(gòu)造器循環(huán)依賴和field循環(huán)依賴。

那么我們要解決循環(huán)引用也應(yīng)該從初始化過程著手,對于單例來說,在Spring容器整個生命周期內(nèi),有且只有一個對象,所以很容易想到這個對象應(yīng)該存在Cache中,Spring為了解決單例的循環(huán)依賴問題,使用了三級緩存。

什么是Spring的三級緩存?

Spring的IOC容器里面的三級緩存都是Map結(jié)構(gòu)。

  • 一級緩存(成熟的bean)
    • singletonObjects 單例池 ,存放完全初始化好的 bean,從該緩存中取出的 bean 可以直接使用
  • 二級緩存
    • earlySingletonObjects 提前曝光的單例對象的cache,存放原始的 bean 對象(尚未填充屬性),用于解決循環(huán)依賴
  • 三級緩存
    • singletonFactories 單例對象工廠的cache,存放 bean 工廠對象,用于解決循環(huán)依賴

【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

OK,了解完三級緩存我們再來看下 getSingleton() 這個方法。這個方法主要是用于從單例池中獲取指定名稱的單例Bean實例,方法內(nèi)部實現(xiàn)了三級緩存查找機制,通過三級查找的機制來獲取指定名稱的單例Bean實例對象,同時該方法會使用同步代碼塊保證多線程環(huán)境下的線程安全性。

【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

OK,那么到這里我們會有一個疑問,Spring為什么要用三級緩存來解決循環(huán)依賴的問題。

首先我們要明確一點,Spring可以解決setter的依賴注入,但是不能解決構(gòu)造器的依賴注入。

假如我們現(xiàn)在有個A對象B對象A的某個field或者setter依賴了B的實例對象,同時B的某個field或者setter依賴了A的實例對象”這種循環(huán)依賴的情況。

A首先完成了初始化的第一步,并且將自己提前曝光到singletonFactories中,此時進(jìn)行初始化的第二步,發(fā)現(xiàn)自己依賴對象B,此時就嘗試去get(B),發(fā)現(xiàn)B還沒有被create,所以走create流程,B在初始化第一步的時候發(fā)現(xiàn)自己依賴了對象A,于是嘗試get(A),嘗試一級緩存singletonObjects(肯定沒有,因為A還沒初始化完全),嘗試二級緩存earlySingletonObjects(也沒有),嘗試三級緩存singletonFactories,由于A通過ObjectFactory將自己提前曝光了,所以B能夠通過ObjectFactory.getObject拿到A對象(雖然A還沒有初始化完全,但是總比沒有好呀),B拿到A對象后順利完成了初始化階段1、2、3,完全初始化之后將自己放入到一級緩存singletonObjects中。

此時返回A中,A此時能拿到B的對象順利完成自己的初始化階段2、3,最終A也完成了初始化,進(jìn)去了一級緩存singletonObjects中,而且更加幸運的是,由于B拿到了A的對象引用,所以B現(xiàn)在hold住的A對象完成了初始化。

【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

知道了這個原理時候,肯定就知道為啥Spring不能解決"A的構(gòu)造方法中依賴了B的實例對象,同時B的構(gòu)造方法中依賴了A的實例對象"這類問題啦!因為加入singletonFactories三級緩存的前提是執(zhí)行了構(gòu)造器,所以構(gòu)造器的循環(huán)依賴沒法解決。

下面一個案例帶大家體驗下構(gòu)造器注入和set注入的演示

編寫類A類B

public class A {
    private B b;
    public A() {}
    public B getB() {
        return b;
    }
    public void setB(B b) {
        this.b = b;
    }
    public void method(){
        System.out.println("A方法調(diào)用");
    }
}
public class B {
    private A a;
    public B(){}
    public A getA() {
        return a;
    }
    public void setA(A a) {
        this.a = a;
    }
    public void method(){
        System.out.println("B方法調(diào)用");
    }
}

編寫xml

    <bean id="b" class="com.lixiang.demo.B">
        <property name="a" ref="a"></property>
    </bean>
    <bean id="a" class="com.lixiang.demo.A">
        <property name="b" ref="b"></property>
    </bean>

測試

【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

修改xml配置

    <bean id="b" class="com.lixiang.demo.B">
        <!--將a改成用構(gòu)造器注入-->
        <constructor-arg name="a" ref="a"></constructor-arg>
    </bean>
    <bean id="a" class="com.lixiang.demo.A">
        <property name="b" ref="b"></property>
    </bean>

代碼調(diào)整

public class B {
    private A a;
    public B(A a){
        this.a = a;
    }
    public A getA() {
        return a;
    }
    public void setA(A a) {
        this.a = a;
    }
    public void method(){
        System.out.println("B方法調(diào)用");
    }
}

測試

【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

可以發(fā)現(xiàn)用構(gòu)造器注入是發(fā)生異常的。

Spring引入了“提前暴露Bean”的機制,在創(chuàng)建A對象時,會先創(chuàng)建一個A的空對象并將其添加到緩存池中。

即“提前暴露Bean”,然后繼續(xù)創(chuàng)建B對象,將其注入A對象中。在創(chuàng)建B對象時,由于A對象已經(jīng)在緩存池中,可以直接獲取到A對象,接著將B對象注入到A對象中,完成Bean的初始化。

【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

好的,到現(xiàn)在整一個Bean的創(chuàng)建流程,就已經(jīng)完成啦。我們在看一下以下三個方法的具體實現(xiàn)。

首先第一個就是 createBeanInstance() 方法
【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

然后是 populateBean() 方法
【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

最后是 initializeBean() 方法
【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程

ok,到這里Spring的bean的創(chuàng)建過程就已經(jīng)梳理完成啦。

記得點個贊+關(guān)注哦!

【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程文章來源地址http://www.zghlxwxcb.cn/news/detail-485577.html

到了這里,關(guān)于【框架源碼】Spring源碼解析之Bean創(chuàng)建源碼流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【Spring】Spring之Bean生命周期源碼解析

    什么是bean的生命周期 是指bean在spring中是如何生成,如何銷毀的; spring創(chuàng)建對象的過程,就是IOC(控制反轉(zhuǎn))的過程; JFR Java Flight Record,java飛行記錄,類似于飛機的黑匣子,是JVM內(nèi)置的基于事件的JDK監(jiān)控記錄框架,主要用于問題定位和持續(xù)監(jiān)控; 入口代碼: Spring啟動的時

    2024年02月15日
    瀏覽(23)
  • 【Spring 】執(zhí)行流程解析:了解Bean的作用域及生命周期

    【Spring 】執(zhí)行流程解析:了解Bean的作用域及生命周期

    ?哈嘍,哈嘍,大家好~ 我是你們的老朋友: 保護(hù)小周?? ? 今天給大家?guī)淼氖?Spring 項目的執(zhí)行流程解析? 和 Bean 對象的6 種作用域 以及 生命周期 , 本文將為大家講解,一起來看看叭~ 本期收錄于博主的專欄 :JavaEE_保護(hù)小周?的博客-CSDN博客 適用于編程初學(xué)者,感興趣

    2024年02月16日
    瀏覽(23)
  • Spring之Bean生命周期源碼解析

    Spring之Bean生命周期源碼解析

    ClassPathBeanDefinitionScanner.java ClassPathScanningCandidateComponentProvider.java 通過組件索引尋找 這里的 componentsIndex 在初始化的時候會嘗試解析 META-INF/spring.components 文件中的配置信息 把斷點打在 ClassPathScanningCandidateComponentProvider 的 setResourceLoader 方法上調(diào)試可以看到堆棧 可以看到,的確

    2024年02月11日
    瀏覽(29)
  • 【深入Spring源碼解析:解密Bean的生命周期】

    Spring是Java企業(yè)級應(yīng)用開發(fā)領(lǐng)域的一顆明星,它提供了很多方便開發(fā)人員的工具和思想。在分布式系統(tǒng)中,Spring的分布式遠(yuǎn)程協(xié)作方案,比如REST、Web服務(wù)以及消息傳遞等,也是不可或缺的。 你知道嗎?在我們使用Spring時,容器中存放的所有對象,在Spring啟動的時候就完成了實

    2024年02月05日
    瀏覽(28)
  • Spring源碼解析(八):bean后置處理器CommonAnnotationBeanPostProcessor

    Spring源碼解析(八):bean后置處理器CommonAnnotationBeanPostProcessor

    Spring源碼系列文章 Spring源碼解析(一):環(huán)境搭建 Spring源碼解析(二):bean容器的創(chuàng)建、默認(rèn)后置處理器、掃描包路徑bean Spring源碼解析(三):bean容器的刷新 Spring源碼解析(四):單例bean的創(chuàng)建流程 Spring源碼解析(五):循環(huán)依賴 Spring源碼解析(六):bean工廠后置處理器ConfigurationCla

    2024年02月13日
    瀏覽(22)
  • Spring源碼之XML文件中Bean標(biāo)簽的解析1

    Spring源碼之XML文件中Bean標(biāo)簽的解析1

    xml文件里包含Bean的信息,為了避免多次IO,需要一次性讀取xml文件中所有bean信息,加入到Spring工廠。 讀取配置文件 ClassPathResource是Spring封裝的一個類型; Resource接口 :可以讀取相關(guān)資源文件的內(nèi)容 獲得輸入流;可讀取的類型,不僅包括本地的xml、 properties、txt 等文件,還包

    2024年02月13日
    瀏覽(27)
  • 【Spring專題】Spring之Bean的生命周期源碼解析——上(掃描生成BeanDefinition)

    【Spring專題】Spring之Bean的生命周期源碼解析——上(掃描生成BeanDefinition)

    由于Spring源碼分析是一個前后聯(lián)系比較強的過程,而且這邊分析,也是按照代碼順序講解的,所以不了解前置知識的情況下,大概率沒辦法看懂當(dāng)前的內(nèi)容。所以,特別推薦看看我前面的文章(自上而下次序): Spring底層核心原理解析——引導(dǎo)篇【學(xué)習(xí)難度: ★★☆☆☆ 】

    2024年02月13日
    瀏覽(22)
  • 【Spring專題】Spring之Bean的生命周期源碼解析——階段一(掃描生成BeanDefinition)

    【Spring專題】Spring之Bean的生命周期源碼解析——階段一(掃描生成BeanDefinition)

    由于Spring源碼分析是一個前后聯(lián)系比較強的過程,而且這邊分析,也是按照代碼順序講解的,所以不了解前置知識的情況下,大概率沒辦法看懂當(dāng)前的內(nèi)容。所以,特別推薦看看我前面的文章(自上而下次序): Spring底層核心原理解析——引導(dǎo)篇【學(xué)習(xí)難度: ★★☆☆☆ 】

    2024年02月13日
    瀏覽(25)
  • 【Spring專題】Spring之Bean的生命周期源碼解析——階段二(IOC之實例化)

    【Spring專題】Spring之Bean的生命周期源碼解析——階段二(IOC之實例化)

    由于Spring源碼分析是一個前后聯(lián)系比較強的過程,而且這邊分析,也是按照代碼順序講解的,所以不了解前置知識的情況下,大概率沒辦法看懂當(dāng)前的內(nèi)容。所以,特別推薦看看我前面的文章(自上而下次序): Spring底層核心原理解析——引導(dǎo)篇【學(xué)習(xí)難度: ★★☆☆☆ 】

    2024年02月13日
    瀏覽(38)
  • 4.是人就能學(xué)會的Spring源碼教程-IOC容器創(chuàng)建Bean對象

    4.是人就能學(xué)會的Spring源碼教程-IOC容器創(chuàng)建Bean對象

    我們要關(guān)注一個接口 BeanFactory ,它是Spring IOC容器的根接口,也是容器的入口。 類的描述中已經(jīng)清楚的說明了: 我們來看一下這個接口里面的方法。 我們可以看到有各種各樣的 getBean 方法,讓我們可以從容器中獲取到各種各樣的Bean對象。 BeanFactory 有一個實現(xiàn)類 DefaultListab

    2024年02月05日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包