溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring的Bean初始化過程和生命周期是什么

發(fā)布時間:2023-03-30 11:52:29 來源:億速云 閱讀:141 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“Spring的Bean初始化過程和生命周期是什么”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

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

    Spring的Bean初始化過程和生命周期是什么

    Spring的Bean初始化過程和生命周期是什么

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

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

    1.加載bean信息

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

    2.實例化bean

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

    • 利用BeanDefinition檢查是否有依賴的bean(配置了@DependOn注解)如有,需要先加載依賴bean

    • 利用BeanDefinition檢查是否單例bean,是走單例bean的創(chuàng)建流程,不是再判斷是否是原型bean,是走原型bean創(chuàng)建,否則都是另一套路徑創(chuàng)建

    • 開始實例化,調(diào)用getSingleton,此時傳入的是對象工廠(ObjectFactory)的實現(xiàn)類,因為對象工廠是函數(shù)式接口,這里傳入的其實就是createBean‘的lamda表達(dá)式

    • 將當(dāng)前bean加入到正在創(chuàng)建bean的一個set

    • 調(diào)用對象工廠的getObject方法,因為我們再上面已經(jīng)傳入了對象工廠(通過lamda表達(dá)式傳入)這里相當(dāng)于調(diào)用剛剛的lamda表達(dá)式,調(diào)用里面的createBean方法

    • createBean去調(diào)了doCreateBean又調(diào)了createBeanInstance,在這里底層通過反射技術(shù)獲取構(gòu)造參數(shù)將對象創(chuàng)建了出來,此時的對象只是通過空參構(gòu)造創(chuàng)建出來的對象,他并沒有任何的屬性。

    • 調(diào)用addSingletonFactory將實例化完成的bean加入到三級緩存,到這里實例化就算是結(jié)束了

    3.bean屬性填充

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

    • populateBean 該方法是填充屬性的入口,傳入beanName和BeanDefinition

    • 從BeanDefinition中獲取屬性注入相關(guān)信息然后判斷是名稱注入還是類型注入

    • 調(diào)用getSingleton從容器中獲取所需對象,若是獲取不到則會重走對象創(chuàng)建的整個流程,拿到完整對象后將其給到當(dāng)前bean的屬性,到這里屬性填充就結(jié)束了

    4.初始化bean

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

    • 判斷有無實現(xiàn)aware接口,如有則去執(zhí)行他的實現(xiàn)類的實現(xiàn)方法,所有aware接口可以參考上圖中所列的三個aware接口,在spring初始化時會對他們進(jìn)行是否實現(xiàn)的判斷

    • 獲取容器中所有postprocessor接口,然后開始執(zhí)行他的前置方法

    • 判斷有無實現(xiàn)初始化接口InitializingBean如有則去執(zhí)行初始化方法afterPropertiesSet

    • 執(zhí)行postprocessor的后置方法,通過前置和后置方法我們可以實現(xiàn)自定義的一些邏輯,不過需要注意的是這些前置和后置方法會作用到所有bean

    5.后置操作

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

    • 將bean從創(chuàng)建中的集合中刪除

    • 將bean加入到單例池中將其從二級三級緩存中刪除

    • 對對象進(jìn)行一些適配操作,到這里完成了初始化的所有操作,后面就是一步步返回調(diào)用的地方了

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

    三、bean的生命周期

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

    1.通過PreDestroy注解修飾方法

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

    2.通過指定destroy-method方法

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

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

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

    下面是對于三種銷毀方式的測試代碼

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

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

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

    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();
        }
    }

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

    Spring的Bean初始化過程和生命周期是什么

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

    “Spring的Bean初始化過程和生命周期是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI