中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

IOC容器啟動和Bean實例化實例分析

發布時間:2022-08-12 10:30:00 來源:億速云 閱讀:136 作者:iii 欄目:開發技術

這篇文章主要介紹“IOC容器啟動和Bean實例化實例分析”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“IOC容器啟動和Bean實例化實例分析”文章能幫助大家解決問題。

IOC 容器的兩個階段

IOC 容器可以分為兩個階段 : 容器啟動階段和 Bean 實例化階段。

Spring 的 IoC 容器在實現的時候, 充分運用了這兩個階段的不同特點, 在每個階段都加入了相應的容器擴展點, 支持開發者根據具體場景的需要, 添加自定義的擴展邏輯.

容器啟動階段

容器啟動, 首先要加載配置元數據 ( Configuration MetaData ).

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

BeanDefinition 對象中保存的屬性很多,如下 :

IOC容器啟動和Bean實例化實例分析

BeanDefinitionRegister 接口用來注冊 BeanDefinition. 該接口的默認實現類為 DefaultListableBeanFactory. 在該實現類中, 有一個成員屬性定義如下 :

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

BeanDefinition 就是被保存到這個 map 中的, key 為 beanName, value 為 BeanDefinition 對象.

Bean 實例化階段

當調用者通過容器的 getBean() 方法明確地想要獲取某個對象, 或者因依賴關系, 容器需要隱式地調用 getBean() 方法時, 就會觸發容器的第二階段.

該階段, 容器會首先檢查所請求的對象之前是否已經初始化. 如果沒有, 則會根據注冊的 BeanDefinition 的信息, 實例化這個對象 , 并為其注入依賴. 如果該對象實現了某些回調接口, 也會根據回調接口的要求來裝配它. 當該對象裝配完畢之后, 容器會立即將其返回給請求方去使用.

Bean 創建的步驟和普通對象的創建步驟不同, 普通的對象在創建時, 由類加載器找到 xxx.class 文件, 然后創建 xxx 對象即可. Spring 中 bean 的創建多了一步, 先是由 類加載器找到 xxx.class 文件, 然后將其解析組裝為 BeanDefinition 對象, 然后 Spring 根據 BeanDefinition 信息來創建對象.

  • 普通對象 : xxx.class -> object

  • Bean 對象 : xxx.class -> BeanDefinition -> bean 對象

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

插手容器的啟動

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

Spring 中自帶的 BeanFactoryPostProcessor 接口的實現:

  • org.springframework.beans. factory.config.PropertyPlaceholderConfigurer占位符機制

  • org.springframework.beans.factory. config.PropertyOverrideConfigurer 重寫屬性值

  • ...

同時也支持開發者通過實現 BeanFactoryPostProcessor 接口自定義擴展.

PropertyPlaceholderConfigurer 占位符機制

PropertyPlaceholderConfigurer 允許開發者在 XML 配置文件中使用占位符, 并將這些占位符所代表的資源單獨配置到簡單的 properties 文件中來加載.

比如將數據庫的連接信息保存在 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>

基本流程 :

  • 當 BeanFactory 在第一階段加載完成所有配置信息時, BeanFactory 中保存的對象的屬性信息還只是以占位符的形式存在, 如 ${jdbc.url}, ${jdbc.driver}.

  • 當 PropertyPlaceholderConfigurer 作為 BeanFactoryPostProcessor 被應用時, 它會使用 properties 配置文件中的配置信息來替換相應 BeanDefinition 中占位符所表示的屬性值.

  • 這樣, 當進入容器實現的第二階段實例化 bean 時, bean 定義中的屬性值就是最終替換完成的了.

PropertyOverrideConfigurer 重寫屬性值

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

PropertyOverrideConfigurer 的 properties 文件中的配置項, 可以覆蓋掉原來 XML 中的 bean 定義的 property 信息.

實例-使用容器擴展點修改 BeanDefinition

此案例使用注解的方式來配置元數據.

現在有兩個類, 一個是 User 類, 一個是 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("調用了 user 的無參數的構造方法");
    }
}
@Data
@AllArgsConstructor
@Accessors(chain = true)
public class Good {
    private int id;
    private String name;
    public Good(){
        System.out.println("調用了 good 的無參數的構造方法");
    }
}

AppConfig 類進行注解的掃描.

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

Test 類用來測試 :

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

運行測試類, 結果如下 :

IOC容器啟動和Bean實例化實例分析

User 類配置了被 Spring 掃描, 所以可以獲取到 user 對象, 而 Good 類沒有配置被掃描, 所以無法獲取 good 對象, 而報錯.

現在我們要做的就是, 讓沒有被 Spring 管理的 Good 類, 也能從 Spring 容器中獲取到它的實例. 實現上述目的的思路就是, 對容器啟動的第一階段生成的 User 類的 BeanDefinition 類做修改.

創建自定義的 BeanFactoryPostProcessor 如下 :

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

然后再次運行測試類, 結果如下 :

IOC容器啟動和Bean實例化實例分析

可以看到,雖然表面上是通過 getBean("user") 來獲取 user 對象,但是實際調用的確實 Good 對象的構造方法,返回的是 good 對象. 但 Good 并沒有讓 Spring 掃描. 這個例子就展示了如何通過 BeanFactoryPostProcessor 機制插手容器的啟動

關于“IOC容器啟動和Bean實例化實例分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

大安市| 贵南县| 徐汇区| 都江堰市| 南雄市| 南澳县| 壶关县| 石屏县| 梅河口市| 台中县| 德安县| 泾川县| 柘荣县| 扶绥县| 白朗县| 伽师县| 刚察县| SHOW| 镇赉县| 三台县| 邛崃市| 祥云县| 思南县| 龙川县| 富顺县| 兴仁县| 蓬莱市| 凌源市| 应用必备| 江口县| 绥化市| 拉孜县| 鄢陵县| 凌海市| 米脂县| 四川省| 石家庄市| 海晏县| 阜新市| 德昌县| 阿图什市|