1. 概述

Spring 框架提供了两种 IOC 容器:BeanFactoryApplicationContext
前者是最基础的 IOC 容器,而后者在 BeanFactory 的基础上进行了功能扩展,提供了更丰富的特性。

本文将通过实际代码示例,深入剖析这两个容器之间的核心差异,帮你避开日常开发中的常见“坑”。

✅ 结论先行:绝大多数场景下应优先选择 ApplicationContext
❌ 仅在内存极度受限(如嵌入式环境)时才考虑使用 BeanFactory


2. 懒加载 vs 预加载

核心区别之一:BeanFactory 是懒加载,ApplicationContext 是预加载(饿汉式)

  • BeanFactory:只有在调用 getBean() 时才会实例化 Bean
  • ApplicationContext:容器启动时自动实例化所有单例 Bean

这意味着 BeanFactory 更轻量,适合资源受限环境;而 ApplicationContext 启动更重,但能提前暴露配置错误。

2.1 BeanFactory 的懒加载示例

定义一个 Student 类,通过静态变量追踪是否被初始化:

public class Student {
    public static boolean isBeanInstantiated = false;

    public void postConstruct() {
        isBeanInstantiated = true;
    }
}

XML 配置中指定初始化方法:

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

测试 BeanFactory 是否在创建容器时就初始化 Bean:

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

⚠️ 此时 Student 并未实例化 —— 只有调用 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()); // ✅ 此时才初始化
}

结论:BeanFactory 是典型的懒加载模式。

2.2 ApplicationContext 的预加载示例

换成 ApplicationContext 实现类 ClassPathXmlApplicationContext

@Test
public void whenAppContInitialized_thenStudentInitialized() {
    ApplicationContext context = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml");
    
    assertTrue(Student.isBeanInstantiated()); // ✅ 即使没调用 getBean,也已初始化
}

⚠️ 关键点:容器一启动,所有单例 Bean 就已完成创建和初始化

这虽然消耗更多内存和启动时间,但好处是:

  • 能在启动阶段发现 Bean 配置问题(比如循环依赖、注入失败)
  • 避免运行时首次访问突然报错

3. 企业级功能支持

ApplicationContext 不只是一个 IOC 容器,更是面向企业应用的完整上下文环境,提供了多项关键能力:

✅ 支持的功能包括:

  • 国际化(i18n):通过 MessageSource 实现多语言支持
  • 事件发布机制:基于 ApplicationEventApplicationListener 的事件驱动模型
  • 注解驱动的依赖注入:如 @Autowired@Value 等开箱即用
  • 无缝集成 Spring AOP:支持声明式事务、切面编程等
  • 支持更多 Bean 作用域:除 singletonprototype 外,还支持 requestsessionapplication 等 Web 级作用域

❌ 相比之下,BeanFactory 仅支持最基本的 singletonprototype 两种作用域,且上述高级功能均需手动注册或根本不可用。

💡 简单粗暴地说:ApplicationContext = BeanFactory + 企业级基础设施


4. 自动注册 BeanProcessor 组件

这是最容易踩坑的一点:ApplicationContext 会自动识别并注册 BeanFactoryPostProcessorBeanPostProcessor 类型的 Bean,而 BeanFactory 不会。

4.1 BeanFactory 需要手动注册

先定义两个处理器用于测试:

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    private static boolean isBeanFactoryPostProcessorRegistered = false;
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory){
        isBeanFactoryPostProcessorRegistered = true;
    }

    // getter/setter
}
public class CustomBeanPostProcessor implements BeanPostProcessor {
    private static boolean isBeanPostProcessorRegistered = false;
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName){
        isBeanPostProcessorRegistered = true;
        return bean;
    }

    // getter/setter
}

XML 中声明这两个 Bean:

<bean id="customBeanPostProcessor" 
  class="com.example.bean.CustomBeanPostProcessor" />
<bean id="customBeanFactoryPostProcessor" 
  class="com.example.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());
    // ❌ 均未注册!
}

⚠️ 必须手动注册才能生效:

@Test
public void whenBFPostProcessorAndBPProcessorRegisteredManually_thenReturnTrue() {
    Resource res = new ClassPathResource("ioc-container-difference-example.xml");
    ConfigurableListableBeanFactory factory = new XmlBeanFactory(res);

    // 手动触发 BeanFactoryPostProcessor
    CustomBeanFactoryPostProcessor bfpp = new CustomBeanFactoryPostProcessor();
    bfpp.postProcessBeanFactory(factory);
    assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());

    // 手动添加 BeanPostProcessor
    CustomBeanPostProcessor bpp = new CustomBeanPostProcessor();
    factory.addBeanPostProcessor(bpp);
    
    Student student = (Student) factory.getBean("student");
    assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}

繁琐且容易遗漏。

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 在初始化过程中会自动扫描并注册所有 BeanFactoryPostProcessorBeanPostProcessor 类型的 Bean。

💡 这也是为什么 Spring 的事务管理(基于 AOP)、@Autowired 注解等功能在 BeanFactory 中默认不生效 —— 它们依赖的底层处理器没有被自动注册!


5. 总结

特性 BeanFactory ApplicationContext
加载策略 懒加载 预加载(启动即实例化单例)
功能完整性 基础 IOC 完整企业级功能支持
国际化支持
事件机制
AOP/事务支持 ❌(需手动) ✅(自动)
BeanPostProcessor 自动注册
适用场景 内存敏感系统(如 IoT) 普通 Web/后端服务

📌 最终建议:

⚠️ 除非你在做嵌入式开发或对内存有极端要求,否则一律使用 ApplicationContext
使用 BeanFactory 很可能导致你“以为配置正确”,结果运行时才发现事务没生效、AOP 不工作等问题 —— 调试成本极高。

文中所有示例代码已托管至 GitHub: 👉 https://github.com/example/spring-core-demo


原始标题:Difference Between BeanFactory and ApplicationContext