前言:为什么我们需要了解这两个容器?
在Spring生态中,BeanFactory和ApplicationContext是支撑整个框架的基石。无论你是刚接触Spring的新手,还是有一定经验的开发者,深入理解这两个核心接口的差异和工作原理,都将为你打开Spring源码学习的大门,提升系统设计和问题排查能力。
一、基础与进阶:两大容器的本质区别
BeanFactory:Spring的"基础版"容器
BeanFactory是Spring框架最基础的IoC容器接口,位于org.springframework.beans.factory包中。它提供了最核心的依赖注入功能,但保持着简约设计的理念。
核心特性:
- Bean实例化、配置和生命周期管理
- 支持懒加载(Lazy Loading)模式
- 简单的Bean查找和获取机制
// 传统使用方式(现代Spring中较少直接使用)
BeanFactory factory = new ClassPathXmlApplicationContext("beans.xml");
UserService service = factory.getBean(UserService.class);
典型实现:
DefaultListableBeanFactory- 最基础的实现XmlBeanFactory- 基于XML配置(已弃用)
ApplicationContext:企业级"全功能"容器
ApplicationContext是BeanFactory的子接口,在基础IoC功能之上,添加了企业应用所需的众多高级特性。
核心增强功能:
- 注解驱动开发 - 自动扫描
@Component、@Service等注解 - 国际化支持 - 便捷的MessageSource消息处理
- 事件发布机制 - 基于观察者模式的ApplicationEvent
- 资源抽象 - 统一的ResourceLoader接口
- AOP无缝集成 - 面向切面编程原生支持
- 环境配置 - Profile和PropertySource管理
关键差异速览
| 特性维度 | BeanFactory | ApplicationContext |
|---|---|---|
| 容器级别 | 基础容器 | 高级容器(超集) |
| 加载策略 | 默认懒加载 | 默认立即初始化 |
| 国际化 | 不支持 | 原生支持 |
| 事件机制 | 无 | 完整发布-订阅模型 |
| 注解支持 | 需手动配置 | 自动扫描注册 |
| AOP集成 | 额外配置 | 开箱即用 |
关系图谱:
BeanFactory (父接口)
↓
ApplicationContext (子接口)
├── ClassPathXmlApplicationContext
├── AnnotationConfigApplicationContext
└── AnnotationConfigServletWebServerApplicationContext (Spring Boot默认)
实践建议: 在现代Spring Boot应用中,ApplicationContext是绝对的主流选择,BeanFactory更多在底层框架扩展时使用。
二、Spring Boot中ApplicationContext的创建过程
启动时间点
ApplicationContext的创建发生在Spring Boot应用启动的初始阶段:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
// 这里会同步创建并初始化ApplicationContext
ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);
}
}
核心初始化流程
ApplicationContext的初始化核心是refresh()方法,这个方法是理解Spring容器启动的关键:
// 简化的refresh流程
public void refresh() {
// 1. 准备阶段 - 设置启动时间、状态标记等
prepareRefresh();
// 2. 创建BeanFactory并加载Bean定义信息(BeanDefinition)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 配置BeanFactory(类加载器、SPEL解析器)
prepareBeanFactory(beanFactory);
// 4. ★ 执行BeanFactory后置处理器
// 这里会解析@Configuration、@Bean等注解
invokeBeanFactoryPostProcessors(beanFactory);
// 5. 注册Bean后置处理器(如@Autowired注解处理器)
registerBeanPostProcessors(beanFactory);
// 6. 初始化消息源、事件广播器等基础组件
initMessageSource();
initApplicationEventMulticaster();
// 7. ★ 特殊Bean初始化(如Spring Boot的嵌入式Web容器)
onRefresh();
// 8. 注册事件监听器
registerListeners();
// 9. ★ 完成BeanFactory初始化 - 实例化所有非懒加载单例Bean
finishBeanFactoryInitialization(beanFactory);
// 10. 完成刷新 - 发布ContextRefreshedEvent事件
finishRefresh();
}
关键步骤说明:
- 步骤4:这里会处理所有
@Configuration类,解析@Bean方法,这是注解驱动开发的核心 - 步骤7:Spring Boot在这里会启动Tomcat、Netty等嵌入式服务器
- 步骤9:这里会实例化所有单例Bean,是依赖注入发生的主要阶段
三、实战中的应用场景与最佳实践
1. 动态Bean获取(谨慎使用)
@Service
public class PaymentService {
@Autowired
private ApplicationContext applicationContext;
public void processPayment(String channel) {
// 根据支付渠道动态获取对应的策略Bean
PaymentStrategy strategy = applicationContext.getBean(
channel + "Payment", PaymentStrategy.class);
strategy.process();
}
}
⚠️ 注意:这种用法破坏了控制反转原则,应该作为最后手段。优先考虑使用Map注入:
@Service
public class PaymentService {
// 更优雅的方式:注入所有PaymentStrategy实现
@Autowired
private Map<String, PaymentStrategy> paymentStrategies;
public void processPayment(String channel) {
PaymentStrategy strategy = paymentStrategies.get(channel + "Payment");
if (strategy != null) {
strategy.process();
}
}
}
2. 事件驱动编程(推荐使用)
事件机制是ApplicationContext提供的最有价值的特性之一:
// 定义领域事件
public class OrderCreatedEvent extends ApplicationEvent {
private final Order order;
public OrderCreatedEvent(Object source, Order order) {
super(source);
this.order = order;
}
// getter...
}
// 发布事件
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public Order createOrder(OrderRequest request) {
Order order = new Order(request);
// ... 保存订单等业务逻辑
// 发布领域事件,解耦相关处理逻辑
eventPublisher.publishEvent(new OrderCreatedEvent(this, order));
return order;
}
}
// 监听事件 - 库存服务
@Component
public class InventoryEventListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 扣减库存,异步处理,业务解耦
inventoryService.deductStock(event.getOrder());
}
}
// 监听事件 - 积分服务
@Component
public class PointsEventListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 增加用户积分
pointsService.addPoints(event.getOrder().getUserId(),
event.getOrder().getAmount());
}
}
3. 环境配置访问
@Component
public class DatabaseConfig {
@Autowired
private Environment env;
@PostConstruct
public void validateConfig() {
String url = env.getProperty("spring.datasource.url");
if (url == null) {
throw new IllegalStateException("数据库URL未配置");
}
}
}
4. 国际化消息处理
@Service
public class NotificationService {
@Autowired
private MessageSource messageSource;
public String getLocalizedMessage(String userLanguage) {
Locale locale = Locale.forLanguageTag(userLanguage);
return messageSource.getMessage("welcome.message",
null, "默认欢迎消息", locale);
}
}
四、最佳实践总结
- 依赖注入优先:99%的场景应该通过
@Autowired注入,而不是手动获取Bean - 善用事件机制:使用事件驱动实现业务解耦,提升代码可维护性
- 避免容器耦合:除非框架扩展,否则不要实现
ApplicationContextAware - 理解生命周期:掌握
refresh()流程有助于排查启动问题和性能优化 - 配置外部化:通过Environment访问配置,而不是硬编码的
@Value