<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為什么大多數(shù)IOC容器使用ApplicationContext,而不用BeanFactory

          共 5859字,需瀏覽 12分鐘

           ·

          2020-11-13 15:38


          1. 引言

          Spring框架附帶了兩個IOC容器–?BeanFactory?和?ApplicationContext.?BeanFactory是IOC容器的最基本版本,ApplicationContext擴展了BeanFactory的功能。那么本篇文章中,我們將通過實際例子了解這兩個IOC容器之間的顯著差異。

          2. 延遲加載 vs. 預加載

          BeanFactory 按需加載bean,而 ApplicationContext 則在啟動時加載所有bean。因此,BeanFactoryApplicationContext相比是輕量級的。讓我們用一個例子來理解它。

          2.1.?BeanFactory?延遲加載

          假設我們有一個名為?Student?單例Bean:

          public?class?Student?{
          ????public?static?boolean?isBeanInstantiated?=?false;
          ?
          ????public?void?postConstruct()?{
          ????????setBeanInstantiated(true);
          ????}
          ?
          ????//standard?setters?and?getters
          }

          我們將把?postConstruct()?方法定義為BeanFactory配置文件?ioc-container-difference-example.xml?中的?init method:

          <bean?id="student"?class="com.baeldung.ioccontainer.bean.Student"?init-method="postConstruct"/>

          現(xiàn)在,讓我們編寫一個測試用例來創(chuàng)建一個BeanFactory?來檢查它是否加載了Student?bean:

          @Test
          public?void?whenBFInitialized_thenStudentNotInitialized()?{
          ????Resource?res?=?new?ClassPathResource("ioc-container-difference-example.xml");
          ????BeanFactory?factory?=?new?XmlBeanFactory(res);
          ????
          ????assertFalse(Student.isBeanInstantiated());
          }

          這里,沒有初始化 Student 對象。換句話說,只有 BeanFactory 被初始化了。只有當我們顯式調(diào)用*getBean()方法時,*BeanFactory 中定義的?bean?才會被加載。讓我們檢查一下?Student?bean 的初始化情況,我們手動調(diào)用?getBean()?方法:

          @Test
          public?void?whenBFInitialized_thenStudentInitialized()?{
          ????Resource?res?=?new?ClassPathResource("ioc-container-difference-example.xml");
          ????BeanFactory?factory?=?new?XmlBeanFactory(res);
          ????Student?student?=?(Student)?factory.getBean("student");
          ?
          ????assertTrue(Student.isBeanInstantiated());
          }

          這里,Student?bean 成功加載。因此,BeanFactory?只在需要時加載bean。

          2.2.?ApplicationContext?預加載

          現(xiàn)在,讓我們用ApplicationContext代替BeanFactory?我們只定義*ApplicationContext,*它將使用預加載策略立即加載所有bean:

          @Test
          public?void?whenAppContInitialized_thenStudentInitialized()?{
          ????ApplicationContext?context?=?new?ClassPathXmlApplicationContext("ioc-container-difference-example.xml");
          ????
          ????assertTrue(Student.isBeanInstantiated());
          }

          在這里,即使我們沒有調(diào)用 getBean() 方法,也會創(chuàng)建 Student 對象?ApplicationContext?被認為是一個沉重的IOC容器,因為它的預加載策略在啟動時加載所有bean。相比之下,BeanFactory?是輕量級的,在內(nèi)存受限的系統(tǒng)中非常方便。盡管如此,大多數(shù)用例仍然首選使用 ApplicationContext,這是為什么呢?

          3. 企業(yè)應用程序功能

          ApplicationContext?以更面向框架的風格增強了BeanFactory,并提供了一些適用于企業(yè)應用程序的功能。

          例如,它提供了消息傳遞(i18n或國際化)功能、事件發(fā)布功能、基于注釋的依賴注入,以及與Spring AOP特性的簡單集成。

          除此之外,ApplicationContext幾乎支持所有類型的 bean 作用域,但是BeanFactory只支持兩個作用域——SingletonPrototype。因此,在構(gòu)建復雜的企業(yè)應用程序時,最好使用ApplicationContext

          4. 自動注冊BeanFactoryPostProcessorBeanPostProcessor

          **ApplicationContext 在啟動時自動注冊 BeanFactoryPostProcessor 和 BeanPostProcessor **。然而,BeanFactory不會自動注冊這些接口。

          4.1. 在 BeanFactory 中注冊

          為了理解,讓我們寫兩個類。首先,我們有CustomBeanFactoryPostProcessor類,它實現(xiàn)了BeanFactoryPostProcessor

          public?class?CustomBeanFactoryPostProcessor?implements?BeanFactoryPostProcessor?{
          ????private?static?boolean?isBeanFactoryPostProcessorRegistered?=?false;
          ????
          ????@Override
          ????public?void?postProcessBeanFactory(ConfigurableListableBeanFactory?beanFactory){
          ????????setBeanFactoryPostProcessorRegistered(true);
          ????}
          ?
          ????//?standard?setters?and?getters
          }

          這里,我們重寫了?postProcessBeanFactory()?方法來檢查它的注冊。其次,我們還有另一個類,CustomBeanPostProcessor,它實現(xiàn)了BeanPostProcessor

          public?class?CustomBeanPostProcessor?implements?BeanPostProcessor?{
          ????private?static?boolean?isBeanPostProcessorRegistered?=?false;
          ????
          ????@Override
          ????public?Object?postProcessBeforeInitialization(Object?bean,?String?beanName){
          ????????setBeanPostProcessorRegistered(true);
          ????????return?bean;
          ????}
          ?
          ????//standard?setters?and?getters
          }

          這里,我們重寫了?PostProcessBeforeAlization()?方法來檢查其注冊。另外,我們在?ioc-container-difference-example.xml?配置文件中配置了這兩個類:

          <bean?id="customBeanPostProcessor"?
          ??class="com.baeldung.ioccontainer.bean.CustomBeanPostProcessor"?/>

          <bean?id="customBeanFactoryPostProcessor"?
          ??class="com.baeldung.ioccontainer.bean.CustomBeanFactoryPostProcessor"?/>

          讓我們看一個測試用例來檢查這兩個類是否在啟動期間自動注冊:

          @Test
          public?void?whenBFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically()?{
          ????Resource?res?=?new?ClassPathResource("ioc-container-difference-example.xml");
          ????ConfigurableListableBeanFactory?factory?=?new?XmlBeanFactory(res);
          ?
          ????assertFalse(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
          ????assertFalse(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
          }

          從我們的測試中我們可以看到,自動注冊并沒有發(fā)生。?現(xiàn)在,讓我們看看一個測試用例,手動將它們添加到 BeanFactory:

          @Test
          public?void?whenBFPostProcessorAndBPProcessorRegisteredManually_thenReturnTrue()?{
          ????Resource?res?=?new?ClassPathResource("ioc-container-difference-example.xml");
          ????ConfigurableListableBeanFactory?factory?=?new?XmlBeanFactory(res);
          ?
          ????CustomBeanFactoryPostProcessor?beanFactoryPostProcessor?
          ??????=?new?CustomBeanFactoryPostProcessor();
          ????beanFactoryPostProcessor.postProcessBeanFactory(factory);
          ????assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
          ?
          ????CustomBeanPostProcessor?beanPostProcessor?=?new?CustomBeanPostProcessor();
          ????factory.addBeanPostProcessor(beanPostProcessor);
          ????Student?student?=?(Student)?factory.getBean("student");
          ????assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
          }

          這里,我們使用?postProcessBeanFactory()?方法注冊?CustomBeanFactoryPostProcessor,使用?addBeanPostProcessor()?方法注冊CustomBeanPostProcessor。在這種情況下,它們都注冊成功。

          4.2. 在?ApplicationContext?中注冊

          如前所述,ApplicationContext會自動注冊這兩個類,而無需編寫額外的代碼。讓我們在單元測試中驗證此行為:

          @Test
          public?void?whenAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically()?{
          ????ApplicationContext?context?
          ??????=?new?ClassPathXmlApplicationContext("ioc-container-difference-example.xml");
          ?
          ????assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
          ????assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
          }

          我們可以看到,這兩個類的自動注冊都是成功的。因此,建議使用ApplicationContext,因為Spring2.0(及更高版本)大量使用BeanPostProcessor。還有一點值得注意的是如果使用的是普通的 BeanFactory,那么事務和AOP之類的功能將不會生效(除非你編寫額外的代碼實現(xiàn),那就另當別論了)。這樣可能會導致代碼很混亂,因為配置看起來貌似沒毛病。

          5. 寫在結(jié)尾

          ApplicationContext?提供了一些高級功能,包括一些面向企業(yè)應用程序的功能,而BeanFactory只提供了基本功能。因此,一般建議使用?ApplicationContext?,只有在內(nèi)存消耗非常關(guān)鍵的情況下,我們才應該考慮去使用BeanFactory。


          DD自研的滬牌代拍業(yè)務,點擊直達



          往期推薦

          JIRA、Confluence等產(chǎn)品明年2月停售本地化版本,將影響中國近90%的客戶!

          妙用 Intellij IDEA 創(chuàng)建臨時文件,Git 跟蹤不到的那種

          Spring Boot 無侵入式 實現(xiàn) API 接口統(tǒng)一 JSON 格式返回

          isEmpty 和 isBlank 區(qū)別?

          國內(nèi)首個比特幣勒索病毒制作者落網(wǎng),但過程有點好笑...

          TIOBE公布11月榜單:Python勢不可擋,超越Java !


          深度內(nèi)容

          推薦加入





          阿里云全線產(chǎn)品超低價,點擊“閱讀原文”進入

          瀏覽 36
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91婷婷五月天丁香社区 | 国产精品久久久违 | 手机AV网站在线观看 | 欧美午夜成人视频 | 国产无圣光 |