最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring中容器的創(chuàng)建流程詳細解讀

 更新時間:2023年10月30日 09:08:16   作者:荊軻刺秦  
這篇文章主要介紹了Spring中容器的創(chuàng)建流程詳細解讀,Spring?框架其本質(zhì)是作為一個容器,提供給應(yīng)用程序需要的對象,了解容器的誕生過程,有助于我們理解?Spring?框架,也便于我們“插手”這個過程,需要的朋友可以參考下

前言

在容器準備階段,需要告知容器從哪里讀取 Bean 信息以及環(huán)境信息。盡管,有時我們并未提供這些信息,但容器依然能正確創(chuàng)建。這得益于一些默認行為(約定大于配置),所以,也不需要由我們主動告知。

1. Bean 的準備

Bean 的準備階段離不開 BeanDefinationRegistry 和 BeanFactory。

這里需要明白 BeanDefination 對象代表的是 Bean 的描述信息。Bean 并不是從一開始就實例化放入容器的。相反,最開始容器只是擁有它的描述信息,所以我們將此階段稱為 Bean 的準備階段。根據(jù)這些描述信息,Spring 能夠創(chuàng)建 Bean,并使它更“完整”。

BeanDefination 在 Spring 中的地位類似于我們的 Class 對象在 JVM 中的地位。

1.1 BeanDefinationRegistry

容器是通過 BeanDefinationRegistry 來注冊 BeanDefination 的。 我們可以通過 xml 文件或者 Java 配置的方式來聲明 BeanDefination,并在創(chuàng)建容器的時候指定 xml 文件或者 Java 類,然后,容器會掃描并注冊 BeanDefination。

那么,此階段我們的機會在哪里呢?其實,Spring 已經(jīng)包含了足夠完善的從定義的 Bean 信息到 BeanDefination 注冊。但如果你仍然想自定義 BeanDefination,或者修改注冊的 BeanDefination ,可以通過獲取 BeanDefinationRegistry 對象。

Spring 通過回調(diào)的方式,調(diào)用實現(xiàn) BeanDefinitionRegistryPostProcessor 接口的類,所以,此類交由 Spring 管理。該類將在后面介紹的刷新階段回調(diào),此為機會一。

Spring 自身也定義了實現(xiàn) BeanDefinitionRegistryPostProcessor 接口的類來完成和我們一樣想要在運行時自定義加載 BeanDefination 的功能,像 ConfigurationClassPostProcessor,調(diào)用時機和我們自定義的一樣,被調(diào)用的順序依賴實現(xiàn) PriorityOrdered 或 Order 接口。

平等對待第三方,在 dubbo 中見過這種說法,或許對于框架開發(fā),這種做法一直很重要。

1.2 BeanFactory

那么,容器中持有的 Bean 一定需要對應(yīng)的 BeanDefination 嘛?這不一定,我們可以直接通過 BeanFactory 來注冊實例化對象。Spring 在將一些環(huán)境信息對象放入容器中,也是這樣做的。

此時,我們的機會又在哪里呢?兩種方式:

  • 實現(xiàn) BeanFactoryAware 接口。
  • 實現(xiàn) BeanFactoryPostProcessor 接口。

實現(xiàn)用于拓展的接口的類都必須交由 Spring 管理才能觸發(fā)回調(diào),此為機會二。上述兩個回調(diào)的時機也都在刷新階段,后續(xù)將詳細敘述。

先做個小結(jié),現(xiàn)在,我們知道了,我們可以通過 BeanDefinationRegistry 操作 BeanDefination,通過 BeanFactory 操作 Bean,那么,如何獲得這兩個對象便是我們的機會所在。

環(huán)境信息

環(huán)境信息包括 profile 和 property,前者可以看作對環(huán)境信息做的分類,因為我們需要在不同時候,激活不同的環(huán)境,像生產(chǎn)和開發(fā)環(huán)境。后者是屬性,屬性可來自不同的屬性源。并且,通過環(huán)境信息,我們可以將 ${} 占位符替換為具體的屬性值。

那么,此時的機會在哪里呢?我們可以自定義一個實現(xiàn) EnvironmentAware 接口的類,此為機會三。

2. 刷新

刷新階段涉及到很多回調(diào),我們將一一分析。

2.1 調(diào)用 BeanFactoryPostProcessors

此階段包含了 BeanDefinitionRegistryPostProcessor 接口的回調(diào),因為 BeanDefinitionRegistryPostProcessor 接口繼承自 BeanFactoryPostProcessor。

調(diào)用順序為:

  • 調(diào)用 BeanDefinitionRegistryPostProcessor;
  • 調(diào)用 BeanFactoryPostProcessor;實現(xiàn)相同接口的對象之間調(diào)用順序?qū)凑?nbsp;PriorityOrdered 和 Ordered 接口來。

2.2 注冊 BeanPostProcessor

BeanPostProcessor 作用于對象初始化前后,我們實現(xiàn)這個接口便可以在對象初始化前后做處理。同樣,實現(xiàn)了該接口后,需要交由 Spring 管理就好。 此階段僅僅是將 BeanPostProcessor 注冊到 BeanFactory 中,并不調(diào)用。注冊順序為:

  1. 實現(xiàn)了 PriorityOrdered 的 BeanPostProcessor;
  2. 實現(xiàn)了 Ordered 的 BeanPostProcessor;
  3. 僅實現(xiàn) BeanPostProcessor;
  4. 實現(xiàn)了 MergedBeanDefinitionPostProcessor

MergedBeanDefinitionPostProcessor 繼承自 BeanPostProcessor。

2.3 實例化所有非延遲實例化的單例

在實例化單例 Bean 時,第一個回調(diào)機會給了 InstantiationAwareBeanPostProcessor 接口,該接口的 postProcessBeforeInstantiation() 方法如果返回了一個對象,該對象將用于存入容器,此為機會四。

如果上面的接口未返回對象,則還允許我們在根據(jù) BeanDefination 創(chuàng)建對象前,再修改 BeanDefination。第二個回調(diào)機會便給了 MergedBeanDefinitionPostProcessor 接口的 postProcessMergedBeanDefinition() 方法。此為機會五。

還有,在存在循環(huán)依賴的時候, 如果你想修改你已經(jīng)放入容器的對象,可以實現(xiàn) SmartInstantiationAwareBeanPostProcessor 接口,該接口的 getEarlyBeanReference() 方法將被調(diào)用。此接口的使用能夠保證其它對象依賴注入的是你修改后的對象,容器中也是你修改后的對象。

比如說 A 依賴了 B,B 依賴了 A。在檢測到 A 依賴 B 的時候,A 已經(jīng)實例化完成,這時候該去走創(chuàng)建B 的過程,然后在創(chuàng)建 B 的過程,發(fā)現(xiàn) A 已經(jīng)創(chuàng)建完成,可以依賴注入,B 的過程正常結(jié)束?;氐絼?chuàng)建 A 的過程,這時,A 也正常注入 B,循環(huán)依賴過程完成了。若此時,你再通過 BeanPostProcessor 重新實例化了對象 A 放入容器,這就會導(dǎo)致容器中的 A 和 B 依賴的 A 不是同一個對象。這違背了單例原則,所以,我們可以通過上述描述的接口來保證。

緊接著的回調(diào)機會給了 InstantiationAwareBeanPostProcessor 接口的 postProcessAfterInstantiation() 方法,此時還未給屬性賦值,但我們可以操作實例化的對象了。

再后來,給了我們修改屬性值的機會,回調(diào) InstantiationAwareBeanPostProcessor 接口的 postProcessProperties() 方法。如果此方法返回 null ,還可再回調(diào) postProcessPropertyValues 方法。

接下來的過程就是初始化了。初始化之前,如果 Bean 實現(xiàn)了以下接口,那么會回調(diào)接口對應(yīng)的方法:

  • BeanNameAware;
  • BeanClassLoaderAware;
  • BeanFactoryAware;

然后,再回調(diào) BeanPostProcessor 的 postProcessBeforeInitialization 方法。 其實,關(guān)于其它 Aware 接口的回調(diào),便是通過 ApplicationContextAwareProcessor 來做的,它是一個 BeanPostProcessor。所以,如果你自定義了一個 Bean,并且實現(xiàn)了 PriorityOrdered 接口,如果它的優(yōu)先級過高,那么它可能在 ApplicationContextAwareProcessor 之前調(diào)用,這樣你某些實現(xiàn)了 Aware 接口的 Bean,可能還尚未獲取 aware 注入的對象。

緊接著,就是調(diào)用 Bean 的初始化方法,實現(xiàn)了 InitializingBean 的 afterPropertiesSet() 方法或者指定的 init-method 方法將被調(diào)用。

初始化完后,便是 BeanPostProcessor 的 postProcessAfterInitialization() 的方法調(diào)用。

至此,容器創(chuàng)建過程的回調(diào)就介紹完了。

3. 寫在最后

我們的機會在于 BeanDefinationRegistry、BeanFactory 以及處理 Bean。需要注意各個回調(diào)接口的調(diào)用時機以及條件,這里整理下具體的回調(diào)順序如下:

  • 前期(BeanFactoryPostProcessor)
    • 處理 BeanDefination: BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry();
    • 處理 BeanFactory: BeanFactoryPostProcessor.postProcessBeanFactory();
  • 創(chuàng)建 Bean(BeanPostProcessor)
    • 自定義實例化:InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(); 自定義實例化過程有很多實現(xiàn)方式,比如 FactoryBean 或者提供一個 Supplier;
    • 實例化前修改 BeanDefination: MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition() ;
    • 實例化后,屬性賦值前:InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
    • 修改屬性(PropertyValue):InstantiationAwareBeanPostProcessor.postProcessProperties(),如果該方法返回 null,還有可以通過 postProcessPropertyValues() 方法來修改。
    • 屬性賦值。
    • 初始化前:BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,BeanPostProcessor.postProcessBeforeInitialization()。
    • 初始化:InitializingBean.afterPropertiesSet() 或者 init-method。
    • 初始化后:BeanPostProcessor.postProcessAfterInitialization()。

梳理完上述過程,再結(jié)合我們自己的需要,就知道我們?nèi)绾瓮卣沽恕?/p>

一個容器的誕生,這個名字聽起來很舒服,這讓我想到一部電影-傳奇的誕生。盡管我所寫的是再平凡不過,但我仍愿為此賦予一個美好的寓意。

到此這篇關(guān)于Spring中容器的創(chuàng)建流程詳細解讀的文章就介紹到這了,更多相關(guān)Spring容器的創(chuàng)建流程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解java線程的開始、暫停、繼續(xù)

    詳解java線程的開始、暫停、繼續(xù)

    本文將介紹通過線程讀取文件內(nèi)容,并且可以控制線程的開始、暫停、繼續(xù),來控制讀文件。具有一定的參考作用,下面跟著小編一起來看下吧
    2017-01-01
  • spring boot 利用注解實現(xiàn)權(quán)限驗證的實現(xiàn)代碼

    spring boot 利用注解實現(xiàn)權(quán)限驗證的實現(xiàn)代碼

    這篇文章主要介紹了spring boot 利用注解實現(xiàn)權(quán)限驗證的實現(xiàn)代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • 基于Socket類以及ServerSocket類的實例講解

    基于Socket類以及ServerSocket類的實例講解

    下面小編就為大家?guī)硪黄赟ocket類以及ServerSocket類的實例講解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • Springcloud seata nacos環(huán)境搭建過程圖解

    Springcloud seata nacos環(huán)境搭建過程圖解

    這篇文章主要介紹了Springcloud seata nacos環(huán)境搭建過程圖解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • SpringBoot整合SpringDataJPA

    SpringBoot整合SpringDataJPA

    這篇文章主要介紹了SpringBoot整合SpringDataJPA代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2021-07-07
  • 使用Spring Initializr創(chuàng)建Spring Boot項目沒有JDK1.8的解決辦法

    使用Spring Initializr創(chuàng)建Spring Boot項目沒有JDK1.8的解決辦法

    很久沒創(chuàng)建springboot項目,今天使用idea的Spring Initializr 創(chuàng)建 Spring Boot項目時,發(fā)現(xiàn)java版本里,無法選擇jdk1.8,只有17、21、22,所以本文介紹了使用Spring Initializr創(chuàng)建Spring Boot項目沒有JDK1.8的解決辦法,需要的朋友可以參考下
    2024-06-06
  • Java多線程之CAS算法實現(xiàn)線程安全

    Java多線程之CAS算法實現(xiàn)線程安全

    這篇文章主要介紹了java中如何通過CAS算法實現(xiàn)線程安全,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,下面小編和大家一起來學(xué)習(xí)一下吧
    2019-05-05
  • spring強行注入和引用實例解析

    spring強行注入和引用實例解析

    這篇文章主要介紹了spring強行注入和引用實例解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • Spring中自動裝配的4種方式

    Spring中自動裝配的4種方式

    今天小編就為大家分享一篇關(guān)于Spring中自動裝配的4種方式,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Spring Aop組成部分及實現(xiàn)步驟

    Spring Aop組成部分及實現(xiàn)步驟

    面向切面編程,是對面向?qū)ο缶幊痰囊环N補充,是一種編程思想,是對某一類的事情的集中處理,這篇文章主要介紹了Spring Aop組成部分及實現(xiàn)步驟,需要的朋友可以參考下
    2023-08-08

最新評論

福州市| 辽阳县| 赤城县| 邢台市| 满城县| 芮城县| 海林市| 芮城县| 东辽县| 清徐县| 海淀区| 阳新县| 福海县| 周宁县| 黔西县| 乌拉特前旗| 堆龙德庆县| 两当县| 霍州市| 鄂托克前旗| 九台市| 黑山县| 吉木萨尔县| 宁都县| 电白县| 米易县| 固始县| 灵璧县| 咸宁市| 新野县| 清流县| 滦平县| 吴桥县| 安图县| 泸定县| 宁海县| 辽宁省| 巴东县| 崇义县| 中卫市| 广宁县|