欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

IOC?容器啟動(dòng)和Bean實(shí)例化兩個(gè)階段詳解

 更新時(shí)間:2022年08月11日 16:24:43   作者:昨天的風(fēng)  
這篇文章主要為大家介紹了IOC?容器啟動(dòng)和Bean實(shí)例化兩個(gè)階段詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

IOC 容器的兩個(gè)階段

IOC 容器可以分為兩個(gè)階段 : 容器啟動(dòng)階段和 Bean 實(shí)例化階段。

Spring 的 IoC 容器在實(shí)現(xiàn)的時(shí)候, 充分運(yùn)用了這兩個(gè)階段的不同特點(diǎn), 在每個(gè)階段都加入了相應(yīng)的容器擴(kuò)展點(diǎn), 支持開發(fā)者根據(jù)具體場(chǎng)景的需要, 添加自定義的擴(kuò)展邏輯.

容器啟動(dòng)階段

容器啟動(dòng), 首先要加載配置元數(shù)據(jù) ( Configuration MetaData ).

容器使用工具類 BeanDefinitionReader 對(duì)加載的配置元數(shù)據(jù)進(jìn)行解析和分析, 并將分析后的信息組裝為相應(yīng)的 Bean 定義對(duì)象 BeanDefinition, 最后把這些保存了 bean 定義必要信息的 BeanDefinition, 注冊(cè)到相應(yīng)的 BeanDefinitionRegistry, 這樣容器啟動(dòng)工作就完成了. ( 將 XML 信息映射到 BeanDefinition 對(duì)象上 )

BeanDefinition 對(duì)象中保存的屬性很多,如下 :

BeanDefinitionRegister 接口用來(lái)注冊(cè) BeanDefinition. 該接口的默認(rèn)實(shí)現(xiàn)類為 DefaultListableBeanFactory. 在該實(shí)現(xiàn)類中, 有一個(gè)成員屬性定義如下 :

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, bean>(64); 

BeanDefinition 就是被保存到這個(gè) map 中的, key 為 beanName, value 為 BeanDefinition 對(duì)象.

Bean 實(shí)例化階段

當(dāng)調(diào)用者通過(guò)容器的 getBean() 方法明確地想要獲取某個(gè)對(duì)象, 或者因依賴關(guān)系, 容器需要隱式地調(diào)用 getBean() 方法時(shí), 就會(huì)觸發(fā)容器的第二階段.

該階段, 容器會(huì)首先檢查所請(qǐng)求的對(duì)象之前是否已經(jīng)初始化. 如果沒(méi)有, 則會(huì)根據(jù)注冊(cè)的 BeanDefinition 的信息, 實(shí)例化這個(gè)對(duì)象 , 并為其注入依賴. 如果該對(duì)象實(shí)現(xiàn)了某些回調(diào)接口, 也會(huì)根據(jù)回調(diào)接口的要求來(lái)裝配它. 當(dāng)該對(duì)象裝配完畢之后, 容器會(huì)立即將其返回給請(qǐng)求方去使用.

Bean 創(chuàng)建的步驟和普通對(duì)象的創(chuàng)建步驟不同, 普通的對(duì)象在創(chuàng)建時(shí), 由類加載器找到 xxx.class 文件, 然后創(chuàng)建 xxx 對(duì)象即可. Spring 中 bean 的創(chuàng)建多了一步, 先是由 類加載器找到 xxx.class 文件, 然后將其解析組裝為 BeanDefinition 對(duì)象, 然后 Spring 根據(jù) BeanDefinition 信息來(lái)創(chuàng)建對(duì)象.

  • 普通對(duì)象 : xxx.class -> object
  • Bean 對(duì)象 : xxx.class -> BeanDefinition -> bean 對(duì)象

可以看到, Spring 在實(shí)例化對(duì)象時(shí), 脫離了配置元數(shù)據(jù)中的信息, 而是使用的 BeanDefinition 中的信息, 這就意味著我們可以修改 BeanDefinition, 從而改變 Spring 生成的對(duì)象的屬性, 甚至是修改最后生成的對(duì)象所屬的類.

插手容器的啟動(dòng)

Spring 提供了一種叫做 BeanFactoryPostProcessor 的容器擴(kuò)展機(jī)制. 該機(jī)制允許開發(fā)者在容器實(shí)例化相應(yīng) Bean 對(duì)象之前, 對(duì)注冊(cè)到容器的 BeanDefinition 的信息做出修改. 即在容器的第一階段的最后進(jìn)行一些自定義操作. 比如修改其中 bean 定義的某些屬性, 為 bean 定義增加其他信息等.

Spring 中自帶的 BeanFactoryPostProcessor 接口的實(shí)現(xiàn):

  • org.springframework.beans. factory.config.PropertyPlaceholderConfigurer占位符機(jī)制
  • org.springframework.beans.factory. config.PropertyOverrideConfigurer 重寫屬性值
  • ...

同時(shí)也支持開發(fā)者通過(guò)實(shí)現(xiàn) BeanFactoryPostProcessor 接口自定義擴(kuò)展.

PropertyPlaceholderConfigurer 占位符機(jī)制

PropertyPlaceholderConfigurer 允許開發(fā)者在 XML 配置文件中使用占位符, 并將這些占位符所代表的資源單獨(dú)配置到簡(jiǎn)單的 properties 文件中來(lái)加載.

比如將數(shù)據(jù)庫(kù)的連接信息保存在 properties 中.

<context:property-placeholder location="classpath:dbconfig.properties" />
<bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
  <property name="driverClass" value="${jdbc.driverClass}"></property>
  <property name="user" value="${jdbc.user}"></property>
  <property name="password" value="${jdbc.password}"></property>
</bean>

基本流程 :

  • 當(dāng) BeanFactory 在第一階段加載完成所有配置信息時(shí), BeanFactory 中保存的對(duì)象的屬性信息還只是以占位符的形式存在, 如 ${jdbc.url}, ${jdbc.driver}.
  • 當(dāng) PropertyPlaceholderConfigurer 作為 BeanFactoryPostProcessor 被應(yīng)用時(shí), 它會(huì)使用 properties 配置文件中的配置信息來(lái)替換相應(yīng) BeanDefinition 中占位符所表示的屬性值.
  • 這樣, 當(dāng)進(jìn)入容器實(shí)現(xiàn)的第二階段實(shí)例化 bean 時(shí), bean 定義中的屬性值就是最終替換完成的了.

PropertyOverrideConfigurer 重寫屬性值

PropertyOverrideConfigurer 允許你對(duì)容器中配置的任何你想處理的 bean 定義的 property 信息進(jìn)行覆蓋替換.

PropertyOverrideConfigurer 的 properties 文件中的配置項(xiàng), 可以覆蓋掉原來(lái) XML 中的 bean 定義的 property 信息.

實(shí)例-使用容器擴(kuò)展點(diǎn)修改 BeanDefinition

此案例使用注解的方式來(lái)配置元數(shù)據(jù).

現(xiàn)在有兩個(gè)類, 一個(gè)是 User 類, 一個(gè)是 Good 類, User 類歸 Spring 管理, 而 Good 類并不歸 Spring 管理. 類的定義如下 :

@Data
@AllArgsConstructor
@Accessors(chain = true)
@Component              //被 Spring 掃描
public class User {
    private int id;
    private String name;
    public User(){
        System.out.println("調(diào)用了 user 的無(wú)參數(shù)的構(gòu)造方法");
    }
}
@Data
@AllArgsConstructor
@Accessors(chain = true)
public class Good {
    private int id;
    private String name;
    public Good(){
        System.out.println("調(diào)用了 good 的無(wú)參數(shù)的構(gòu)造方法");
    }
}

AppConfig 類進(jìn)行注解的掃描.

@ComponentScan(value = {"it.com"})
public class AppConfig {
}

Test 類用來(lái)測(cè)試 :

public static void main(String[] args){
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    User user = (User) context.getBean("user");
    Good good = (Good) context.getBean("good");
}

運(yùn)行測(cè)試類, 結(jié)果如下 :

User 類配置了被 Spring 掃描, 所以可以獲取到 user 對(duì)象, 而 Good 類沒(méi)有配置被掃描, 所以無(wú)法獲取 good 對(duì)象, 而報(bào)錯(cuò).

現(xiàn)在我們要做的就是, 讓沒(méi)有被 Spring 管理的 Good 類, 也能從 Spring 容器中獲取到它的實(shí)例. 實(shí)現(xiàn)上述目的的思路就是, 對(duì)容器啟動(dòng)的第一階段生成的 User 類的 BeanDefinition 類做修改.

創(chuàng)建自定義的 BeanFactoryPostProcessor 如下 :

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 通過(guò) Spring 中 bean 的名字獲取到指定的 bean
        GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("user");
        // 輸出 beanDefinition 的信息
        System.out.println(beanDefinition.getBeanClass());
        System.out.println(beanDefinition.getFactoryBeanName());
        // 然后進(jìn)行貍貓換太子,將 User 類對(duì)應(yīng)的 BeanDefinition 對(duì)象的 beanClass 屬性替換掉
        beanDefinition.setBeanClass(Good.class);
    }
}

然后再次運(yùn)行測(cè)試類, 結(jié)果如下 :

可以看到,雖然表面上是通過(guò) getBean("user") 來(lái)獲取 user 對(duì)象,但是實(shí)際調(diào)用的確實(shí) Good 對(duì)象的構(gòu)造方法,返回的是 good 對(duì)象. 但 Good 并沒(méi)有讓 Spring 掃描. 這個(gè)例子就展示了如何通過(guò) BeanFactoryPostProcessor 機(jī)制插手容器的啟動(dòng)

以上就是IOC 容器啟動(dòng)和Bean實(shí)例化兩個(gè)階段詳解的詳細(xì)內(nèi)容,更多關(guān)于IOC 容器啟動(dòng)Bean實(shí)例化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot注入自定義的配置文件的方法詳解

    SpringBoot注入自定義的配置文件的方法詳解

    在實(shí)際的項(xiàng)目開發(fā)過(guò)程中,我們經(jīng)常需要將某些變量從代碼里面抽離出來(lái),放在配置文件里面。今天,我們就一起來(lái)聊一聊SpringBoot加載配置文件的幾種玩法,需要的可以參考一下
    2022-09-09
  • Intellij IDEA 關(guān)閉和開啟自動(dòng)更新的提示?

    Intellij IDEA 關(guān)閉和開啟自動(dòng)更新的提示?

    這篇文章主要介紹了Intellij IDEA 關(guān)閉和開啟自動(dòng)更新的提示操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • maven子模塊相互依賴打包時(shí)報(bào)錯(cuò)找不到類的解決方案

    maven子模塊相互依賴打包時(shí)報(bào)錯(cuò)找不到類的解決方案

    本文主要介紹了maven子模塊相互依賴打包時(shí)報(bào)錯(cuò)找不到類的解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Java實(shí)現(xiàn)學(xué)生管理系統(tǒng)(IO版)

    Java實(shí)現(xiàn)學(xué)生管理系統(tǒng)(IO版)

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Spring MVC下 bootStrap服務(wù)器分頁(yè)代碼

    Spring MVC下 bootStrap服務(wù)器分頁(yè)代碼

    因?yàn)镾pring 對(duì)于ajax直接返回對(duì)象,到了WEB頁(yè)面就轉(zhuǎn)換成json 所以不需要使用JSON轉(zhuǎn)換封裝可以直接使用。接下來(lái)通過(guò)本文給大家分享Spring MVC下 bootStrap服務(wù)器分頁(yè)代碼,需要的的朋友參考下
    2017-03-03
  • Java中方法使用的深入講解

    Java中方法使用的深入講解

    這篇文章主要給大家介紹了關(guān)于Java中方法使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • SpringBoot安全認(rèn)證Security的實(shí)現(xiàn)方法

    SpringBoot安全認(rèn)證Security的實(shí)現(xiàn)方法

    這篇文章主要介紹了SpringBoot安全認(rèn)證Security的實(shí)現(xiàn)方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-05-05
  • IDEA插件之彩虹括號(hào)Rainbow?Brackets使用介紹

    IDEA插件之彩虹括號(hào)Rainbow?Brackets使用介紹

    這篇文章主要為大家介紹了IDEA插件之彩虹括號(hào)Rainbow?Brackets使用介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Mybatis整合Spring 由于版本引起的BUG問(wèn)題

    Mybatis整合Spring 由于版本引起的BUG問(wèn)題

    這篇文章主要介紹了Mybatis整合Spring 由于版本引起的BUG問(wèn)題,需要的朋友可以參考下
    2017-06-06
  • Java請(qǐng)求Http接口OkHttp超詳細(xì)講解(附帶工具類)

    Java請(qǐng)求Http接口OkHttp超詳細(xì)講解(附帶工具類)

    這篇文章主要給大家介紹了關(guān)于Java請(qǐng)求Http接口OkHttp超詳細(xì)講解的相關(guān)資料,OkHttp是一款優(yōu)秀的HTTP客戶端框架,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2024-02-02

最新評(píng)論