1. 概述
Spring 框架提供了两种 IOC 容器:BeanFactory 和 ApplicationContext。
前者是最基础的 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
实现多语言支持 - 事件发布机制:基于
ApplicationEvent
和ApplicationListener
的事件驱动模型 - 注解驱动的依赖注入:如
@Autowired
、@Value
等开箱即用 - 无缝集成 Spring AOP:支持声明式事务、切面编程等
- 支持更多 Bean 作用域:除
singleton
和prototype
外,还支持request
、session
、application
等 Web 级作用域
❌ 相比之下,BeanFactory
仅支持最基本的 singleton
和 prototype
两种作用域,且上述高级功能均需手动注册或根本不可用。
💡 简单粗暴地说:
ApplicationContext = BeanFactory + 企业级基础设施
4. 自动注册 BeanProcessor 组件
这是最容易踩坑的一点:ApplicationContext 会自动识别并注册 BeanFactoryPostProcessor
和 BeanPostProcessor
类型的 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
在初始化过程中会自动扫描并注册所有 BeanFactoryPostProcessor
和 BeanPostProcessor
类型的 Bean。
💡 这也是为什么 Spring 的事务管理(基于 AOP)、
@Autowired
注解等功能在BeanFactory
中默认不生效 —— 它们依赖的底层处理器没有被自动注册!
5. 总结
特性 | BeanFactory | ApplicationContext |
---|---|---|
加载策略 | 懒加载 | 预加载(启动即实例化单例) |
功能完整性 | 基础 IOC | 完整企业级功能支持 |
国际化支持 | ❌ | ✅ |
事件机制 | ❌ | ✅ |
AOP/事务支持 | ❌(需手动) | ✅(自动) |
BeanPostProcessor 自动注册 | ❌ | ✅ |
适用场景 | 内存敏感系统(如 IoT) | 普通 Web/后端服务 |
📌 最终建议:
⚠️ 除非你在做嵌入式开发或对内存有极端要求,否则一律使用
ApplicationContext
。
使用BeanFactory
很可能导致你“以为配置正确”,结果运行时才发现事务没生效、AOP 不工作等问题 —— 调试成本极高。
文中所有示例代码已托管至 GitHub: 👉 https://github.com/example/spring-core-demo