知識庫 / Spring RSS 訂閱

BeanFactory 與 ApplicationContext 的區別

Spring
HongKong
11
01:01 PM · Dec 06 ,2025

1. 概述

Spring 框架提供了兩個依賴注入 (IOC) 容器:<em >BeanFactory</em><em >ApplicationContext</em><em >BeanFactory</em> 是最基礎的 IOC 容器版本,而 <em >ApplicationContext</em> 擴展了 <em >BeanFactory</em> 的功能。

在本快速教程中,我們將通過實際示例,理解這兩個 IOC 容器之間的主要差異。

2. 按需加載與即時加載

<em>BeanFactory</em> 在需要時才加載 Bean,而 <em>ApplicationContext</em> 在啓動時加載所有 Bean。因此,<em>BeanFactory</em><em>ApplicationContext</em> 輕量級。我們通過一個例子來理解這一點。

2.1. 延遲加載中使用 BeanFactory

假設我們有一個名為 Student 的單例 Bean 類,該類包含一個方法:

public class Student {
    public static boolean isBeanInstantiated = false;

    public void postConstruct() {
        setBeanInstantiated(true);
    }

    //standard setters and getters
}

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

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

現在,我們來編寫一個測試用例,創建一個 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被初始化。我們定義的BeanFactory中的Bean只有在我們顯式調用getBean()方法時才會加載。

讓我們檢查我們手動調用getBean()方法時,Student Bean 的初始化情況:

@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 進行立即加載

現在,我們將使用 ApplicationContext 來替代 BeanFactory

我們將僅定義 ApplicationContext,它將通過立即加載策略立即加載所有 bean:

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

這裏創建了 Student 對象,儘管我們尚未調用 getBean() 方法。

ApplicationContext 被認為是重型 IOC 容器,因為它採用急加載策略,在啓動時加載所有 Bean。相比之下,BeanFactory 則輕量級,在內存受限的系統中非常實用。儘管如此,在下一部分,我們將看到為什麼 ApplicationContext 在大多數用例中更受歡迎.

3. 企業應用程序功能

ApplicationContext 增強了BeanFactory,並以更具框架化的方式提供了多種功能,適用於企業應用程序。

例如,它提供消息傳遞(國際化或國際化)功能,事件發佈功能,基於註解的依賴注入,以及與 Spring AOP 功能的輕鬆集成

此外,ApplicationContext 支持幾乎所有類型的 Bean 作用域,但BeanFactory 僅支持兩個作用域——單例原型。因此,在構建複雜的企業應用程序時,最好始終使用ApplicationContext

4. 自動註冊 BeanFactoryPostProcessorBeanPostProcessor

`ApplicationContext 會在啓動時自動註冊 BeanFactoryPostProcessorBeanPostProcessor。 相反,BeanFactory 不會自動註冊這些接口。

4.1. 在 BeanFactory 中註冊

為了理解,我們來編寫兩個類。

首先,我們有 CustomBeanFactoryPostProcessor 類,它實現了 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,它實現了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
}

在這裏,我們覆蓋了 postProcessBeforeInitialization() 方法,以檢查其是否已註冊。

此外,我們還配置了 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());
}

如我們所見,從我們的測試中可以看出,自動註冊並未發生

現在,讓我們來看一個手動在 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,因為 Spring 2.0 (及更高版本) 強烈依賴 BeanPostProcessor

此外,還值得注意的是,如果您使用的是純粹的 BeanFactory,那麼諸如事務和 AOP 等功能將不會生效 (至少在不編寫額外的代碼行的情況下)。 這可能會導致混淆,因為配置本身看起來沒有任何問題。

5. 結論

在本文中,我們探討了 <em >ApplicationContext</em >><em >BeanFactory</em >> 之間的關鍵差異,並通過實際示例進行了説明。

<em >ApplicationContext</em >> 提供了高級功能,包括針對企業應用程序的多種特性,而 <em >BeanFactory</em >> 則僅提供基本功能。因此,通常建議使用 <em >ApplicationContext</em >>,並且在內存消耗至關重要時,我們應該使用 <em >BeanFactory</em >>

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.