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

一文帶你了解Spring的Bean初始化過(guò)程和生命周期

 更新時(shí)間:2023年03月30日 10:07:57   作者:歸去來(lái) 兮  
Spring的核心功能有三點(diǎn)IOC、DI、AOP,IOC則是基礎(chǔ),也是Spring功能的最核心的點(diǎn)之一。今天一起來(lái)總結(jié)下Spring中Bean是怎么被創(chuàng)建出來(lái)的

一、Spring創(chuàng)建bean的流程圖

下圖是筆者多次翻看IOC源碼后總結(jié)出來(lái)的bean 創(chuàng)建的詳細(xì)過(guò)程,借助該圖可以很快的理解相關(guān)源碼

二、Spring創(chuàng)建bean的詳細(xì)流程

上面的流程圖其實(shí)已經(jīng)可以很清晰的看到bean的創(chuàng)建過(guò)程了,這里結(jié)合圖片我們一起來(lái)詳細(xì)說(shuō)下這個(gè)過(guò)程,這里不貼源碼,貼了源碼只會(huì)讓觀看的人比較迷糊,若是想跟源碼的可以對(duì)照上面的流程圖完全能做到源碼復(fù)現(xiàn),bean創(chuàng)建的這個(gè)過(guò)程大致可以分為五步:加載bean信息,實(shí)例化bean,bean屬性填充,初始化bean,后置操作,那我們就基于這五大步來(lái)看看Spring是如何創(chuàng)建bean的。

1.加載bean信息

被IOC注解修飾的類,或者通過(guò)xml配置的類,首先在容器啟動(dòng)時(shí)一refresh方法為入口,會(huì)將這些類掃描進(jìn)來(lái)形成BeanDefinition信息,BeanDefinition就是包含了我們配置的一些bean的屬性,比如是否單例,是否有bean依賴(DependOn),bean的名稱,bean所屬class的全路徑等,這里存儲(chǔ)的相當(dāng)于bean的元信息,然后通過(guò) BeanDefinitionRegistry將這些BeanDefinition加載進(jìn)來(lái)后面我們就可以利用該信息了,且在Spring創(chuàng)建Bean的全程都需要BeanDefinition的參與,所以他很重要。

2.實(shí)例化bean

通過(guò)上面的圖可以清晰看到在實(shí)例化階段之前其實(shí)還有很多小的操作:容器會(huì)先去嘗試getBean–>doGetBean–>getSingleton等操作在這些操作都拿不到對(duì)象以后才會(huì)開始著手創(chuàng)建對(duì)象,需要說(shuō)的是getSingleton會(huì)嘗試從三級(jí)緩存中依次去獲取Bean,當(dāng)所有緩存都獲取不到時(shí)就可以確認(rèn)當(dāng)前bean沒(méi)有被創(chuàng)建,然后就可以啟動(dòng)創(chuàng)建的相關(guān)動(dòng)作

  • 利用BeanDefinition檢查是否有依賴的bean(配置了@DependOn注解)如有,需要先加載依賴bean
  • 利用BeanDefinition檢查是否單例bean,是走單例bean的創(chuàng)建流程,不是再判斷是否是原型bean,是走原型bean創(chuàng)建,否則都是另一套路徑創(chuàng)建
  • 開始實(shí)例化,調(diào)用getSingleton,此時(shí)傳入的是對(duì)象工廠(ObjectFactory)的實(shí)現(xiàn)類,因?yàn)閷?duì)象工廠是函數(shù)式接口,這里傳入的其實(shí)就是createBean‘的lamda表達(dá)式
  • 將當(dāng)前bean加入到正在創(chuàng)建bean的一個(gè)set
  • 調(diào)用對(duì)象工廠的getObject方法,因?yàn)槲覀冊(cè)偕厦嬉呀?jīng)傳入了對(duì)象工廠(通過(guò)lamda表達(dá)式傳入)這里相當(dāng)于調(diào)用剛剛的lamda表達(dá)式,調(diào)用里面的createBean方法
  • createBean去調(diào)了doCreateBean又調(diào)了createBeanInstance,在這里底層通過(guò)反射技術(shù)獲取構(gòu)造參數(shù)將對(duì)象創(chuàng)建了出來(lái),此時(shí)的對(duì)象只是通過(guò)空參構(gòu)造創(chuàng)建出來(lái)的對(duì)象,他并沒(méi)有任何的屬性。
  • 調(diào)用addSingletonFactory將實(shí)例化完成的bean加入到三級(jí)緩存,到這里實(shí)例化就算是結(jié)束了

3.bean屬性填充

屬性填充其實(shí)就為自身屬性進(jìn)行賦值的過(guò)程,根據(jù)我們的DI注解這里會(huì)先從三個(gè)緩存中獲取bean,若是獲取不到,則會(huì)嘗試進(jìn)行bean的創(chuàng)建,若是走到了bean的創(chuàng)建,則會(huì)重新走一邊bean創(chuàng)建的整個(gè)流程,這里是遞歸邏輯。

  • populateBean 該方法是填充屬性的入口,傳入beanName和BeanDefinition
  • 從BeanDefinition中獲取屬性注入相關(guān)信息然后判斷是名稱注入還是類型注入
  • 調(diào)用getSingleton從容器中獲取所需對(duì)象,若是獲取不到則會(huì)重走對(duì)象創(chuàng)建的整個(gè)流程,拿到完整對(duì)象后將其給到當(dāng)前bean的屬性,到這里屬性填充就結(jié)束了

4.初始化bean

屬性填充完畢后并沒(méi)有立即結(jié)束這個(gè)過(guò)程,還有一些其他的操作需要spring進(jìn)行處理,比如aware接口的處理,postprocessor接口的處理,初始化的處理等操作其實(shí)這里主要就是處理這三個(gè)動(dòng)作的

  • 判斷有無(wú)實(shí)現(xiàn)aware接口,如有則去執(zhí)行他的實(shí)現(xiàn)類的實(shí)現(xiàn)方法,所有aware接口可以參考上圖中所列的三個(gè)aware接口,在spring初始化時(shí)會(huì)對(duì)他們進(jìn)行是否實(shí)現(xiàn)的判斷
  • 獲取容器中所有postprocessor接口,然后開始執(zhí)行他的前置方法
  • 判斷有無(wú)實(shí)現(xiàn)初始化接口InitializingBean如有則去執(zhí)行初始化方法afterPropertiesSet
  • 執(zhí)行postprocessor的后置方法,通過(guò)前置和后置方法我們可以實(shí)現(xiàn)自定義的一些邏輯,不過(guò)需要注意的是這些前置和后置方法會(huì)作用到所有bean

5.后置操作

這里的后置操作,主要是完成一些清掃工作和適配工作,比如刪除二級(jí)、三級(jí)緩存中無(wú)用的bean引用等,下面是具體操作。

  • 將bean從創(chuàng)建中的集合中刪除
  • 將bean加入到單例池中將其從二級(jí)三級(jí)緩存中刪除
  • 對(duì)對(duì)象進(jìn)行一些適配操作,到這里完成了初始化的所有操作,后面就是一步步返回調(diào)用的地方了

看了這五步,不知道是不是對(duì)bean的創(chuàng)建過(guò)程有了清晰的認(rèn)識(shí),如果還是不夠清晰可以根據(jù)第一部分的流程圖走下代碼,代碼走兩遍其實(shí)就會(huì)比較清晰了。

三、bean的生命周期

bean的生命周期其實(shí)就是從創(chuàng)建到銷毀,上面創(chuàng)建已經(jīng)說(shuō)完了,其實(shí)只差銷毀這一步了。bean銷毀發(fā)生在容器關(guān)閉時(shí)對(duì)單例bean進(jìn)行清除操作。在Spring中我們通常有三種方式定義bean銷毀時(shí)的邏輯

1.通過(guò)PreDestroy注解修飾方法

Bean銷毀時(shí)會(huì)檢查有無(wú)該注解修飾的方法,如有,會(huì)對(duì)該注解修飾的方法進(jìn)行執(zhí)行

2.通過(guò)指定destroy-method方法

在使用xml對(duì)bean進(jìn)行注入時(shí),我們可以指定init-method方法,也可以指定destroy-method方法,同樣的使用Bean注解時(shí)也是支持這兩個(gè)屬性的,Spring容器關(guān)閉時(shí)會(huì)尋找當(dāng)前bean有無(wú)指定destroy-method,如有則會(huì)進(jìn)行執(zhí)行

3.實(shí)現(xiàn)DisposableBean接口

實(shí)現(xiàn)該接口重寫他的destroy方法,同樣的Spring容器關(guān)閉時(shí)也會(huì)檢查有無(wú)實(shí)現(xiàn)該接口,如有實(shí)現(xiàn)也會(huì)執(zhí)行這里的銷毀方法

下面是對(duì)于三種銷毀方式的測(cè)試代碼

第一端是自定義Spring容器,給容器注冊(cè)鉤子,這樣當(dāng)我們關(guān)閉Spring容器時(shí)會(huì)自動(dòng)調(diào)用我們的銷毀方法

public class AppStartClass {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(yuCloseSpring.class);
        annotationConfigApplicationContext.start();
        annotationConfigApplicationContext.registerShutdownHook();
    }

這一段是測(cè)試代碼了,分別使用三種方式寫了銷毀方法

public class MyDisposableBean  implements DisposableBean{


    @Override
    public void destroy() throws Exception {
        System.out.println("執(zhí)行DisposableBean的銷毀方法");

    }

    public void test(){
        System.out.println("執(zhí)行destroy-method銷毀方法");
    }

    @PreDestroy
    public void testPreDestroy(){
        System.out.println("執(zhí)行PreDestroy注解修飾的銷毀方法");
    }

}
@Configuration
class yuCloseSpring{

    @Bean(destroyMethod = "test")
    public MyDisposableBean getMyDisposableBean(){
        return  new MyDisposableBean();
    }
}

下面是啟動(dòng)main方法后的執(zhí)行截圖,可以清晰的看到三種銷毀方法都是正常執(zhí)行的,且他們執(zhí)行順序是固定的,即:PreDestroy–>DisposableBean–>destroy-method。

到這里其實(shí)bean整個(gè)生命周期就算是徹底結(jié)束了。

四、總結(jié)

這篇主要總結(jié)Spring中bean的創(chuàng)建過(guò)程,主要分為==加載bean信息–>實(shí)例化bean–>屬性填充–>初始化階段–>后置處理等步驟,且每個(gè)步驟Spring做的事情都很多,這塊源碼還是很值得我們都去看一看的。==而Spring中Bean的聲明周期其實(shí)就是創(chuàng)建到使用到銷毀,使用應(yīng)該沒(méi)啥需要說(shuō)的,銷毀在第三部分也正常介紹了三種銷毀的方式。希望這一篇可以對(duì)路過(guò)的你有所幫助。

以上就是一文帶你了解Spring的Bean初始化過(guò)程和生命周期的詳細(xì)內(nèi)容,更多關(guān)于Spring Bean初始化和生命周期的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • IDEA高效使用設(shè)置指南

    IDEA高效使用設(shè)置指南

    本文主要為大家介紹了關(guān)于IDEA高效的設(shè)置指南,其中包含必備的一些插件推薦以及主題優(yōu)化還有IDEA源碼的閱讀技巧,干貨滿滿,有需要的朋友可以借鑒參考下
    2022-01-01
  • SpringBoot電腦商城項(xiàng)目刪除收貨地址的實(shí)現(xiàn)方法

    SpringBoot電腦商城項(xiàng)目刪除收貨地址的實(shí)現(xiàn)方法

    這篇文章主要介紹了SpringBoot項(xiàng)目--電腦商城刪除收貨地址功能實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • java.lang.NoSuchMethodException: com.sun.proxy.$Proxy58.list錯(cuò)誤解決辦法

    java.lang.NoSuchMethodException: com.sun.proxy.$Proxy58.list

    這篇文章主要介紹了java.lang.NoSuchMethodException: com.sun.proxy.$Proxy58.list錯(cuò)誤解決辦法的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • Spring MVC異常處理機(jī)制示例詳解

    Spring MVC異常處理機(jī)制示例詳解

    這篇文章主要給大家介紹了關(guān)于Spring MVC異常處理機(jī)制的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring MVC具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • 完美解決springboot中使用mybatis字段不能進(jìn)行自動(dòng)映射的問(wèn)題

    完美解決springboot中使用mybatis字段不能進(jìn)行自動(dòng)映射的問(wèn)題

    今天在springboot中使用mybatis的時(shí)候不能字段不能夠進(jìn)行自動(dòng)映射,接下來(lái)給大家給帶來(lái)了完美解決springboot中使用mybatis字段不能進(jìn)行自動(dòng)映射的問(wèn)題,需要的朋友可以參考下
    2023-05-05
  • HashMap實(shí)現(xiàn)保存兩個(gè)key相同的數(shù)據(jù)

    HashMap實(shí)現(xiàn)保存兩個(gè)key相同的數(shù)據(jù)

    這篇文章主要介紹了HashMap實(shí)現(xiàn)保存兩個(gè)key相同的數(shù)據(jù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Spring使用AOP完成統(tǒng)一結(jié)果封裝實(shí)例demo

    Spring使用AOP完成統(tǒng)一結(jié)果封裝實(shí)例demo

    這篇文章主要介紹了Spring使用AOP完成統(tǒng)一結(jié)果封裝,本文通過(guò)實(shí)現(xiàn)demo給大家詳細(xì)講解,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-02-02
  • spring boot在啟動(dòng)項(xiàng)目之后執(zhí)行的實(shí)現(xiàn)方法

    spring boot在啟動(dòng)項(xiàng)目之后執(zhí)行的實(shí)現(xiàn)方法

    在開發(fā)時(shí)有時(shí)候需要在整個(gè)應(yīng)用開始運(yùn)行時(shí)執(zhí)行一些特定代碼,比如初始化環(huán)境,下面這篇文章就來(lái)給大家介紹了關(guān)于spring boot在啟動(dòng)項(xiàng)目之后執(zhí)行自己要執(zhí)行的東西的實(shí)現(xiàn)方法,文中給出了詳細(xì)的示例代碼,需要的朋友可以參考下。
    2017-09-09
  • 深入分析@Resource和@Autowired注解區(qū)別

    深入分析@Resource和@Autowired注解區(qū)別

    這篇文章主要為大家介紹了深入分析@Resource和@Autowired注解區(qū)別,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • Java Socket編程實(shí)例(四)- NIO TCP實(shí)踐

    Java Socket編程實(shí)例(四)- NIO TCP實(shí)踐

    這篇文章主要講解Java Socket編程中NIO TCP的實(shí)例,希望能給大家做一個(gè)參考。
    2016-06-06

最新評(píng)論