系列文章第2篇 | 共3篇
难度:⭐⭐⭐ | 适合人群:想深入理解Spring容器的开发者
📝 上期回顾
上一篇我们学习了:
- ✅ IoC(控制反转)和DI(依赖注入)的概念
- ✅ 手写了100行代码实现简易IoC容器
- ✅ 理解了Spring的BeanFactory接口
- ✅ 掌握了Bean的注册、创建、注入流程
上期思考题解答:
Q1: 如何改造支持Setter注入?
A: 在createBean()方法中,创建对象后,通过反射调用setter方法注入依赖。(本篇会演示)
Q2: 循环依赖会怎样?Spring如何解决?
A: 我们的容器会栈溢出,Spring通过"三级缓存"解决。(第三篇详解)
Q3: BeanFactory和ApplicationContext有什么区别?
A: 今天详细解答!
💥 开场:一次生产事故的教训
时间: 周五晚上10点
地点: 家里(刚准备睡觉)
事件: 生产告警
手机响起: 📱 "叮叮叮!"
告警信息: "订单服务启动缓慢,超时30秒!"
我: "啥情况?" 😰(赶紧打开电脑)
查看日志:
2024-01-20 22:05:00 INFO - 开始启动Spring容器...
2024-01-20 22:05:00 INFO - 加载配置文件...
2024-01-20 22:05:01 INFO - 扫描Bean定义...
2024-01-20 22:05:02 INFO - 创建UserService...
2024-01-20 22:05:03 INFO - 创建OrderService...
2024-01-20 22:05:04 INFO - 创建PaymentService...
...
2024-01-20 22:05:28 INFO - 创建NotificationService...
2024-01-20 22:05:29 INFO - 所有Bean创建完成
2024-01-20 22:05:30 INFO - 容器启动完成!
我: "卧槽,启动30秒?上周还是3秒!" 😱
第二天,找架构师老李:
我: "李哥,容器启动越来越慢,有办法优化吗?"
老李: "你用的什么容器?"
我: "BeanFactory啊,上次你说的..."
老李: "等等,生产环境用BeanFactory?" 😨
我: "有问题吗?"
老李: "问题大了!BeanFactory是懒加载,每次getBean都要创建,启动快但运行慢。生产环境应该用ApplicationContext,启动时就把所有Bean创建好,运行时直接用!"
我: "原来如此!那ApplicationContext和BeanFactory有什么区别?" 🤔
老李: "区别大了,至少7个!来,我给你画个图..."
🤔 第一问:ApplicationContext是什么?
Q1:先看继承关系
类图:
BeanFactory (爷爷)
↑
|
ApplicationContext (父亲)
↑
|
┌─────────┼─────────┐
| | |
ClassPath FileSystem Web
↑ ↑ ↑
| | |
XML/ XML/ XML/
Annotation Annotation Annotation
发现: ApplicationContext继承了BeanFactory!
结论: ApplicationContext 是一个BeanFactory,但功能更强!
Q2:ApplicationContext接口定义
位置: org.springframework.context.ApplicationContext
源码(简化版):
public interface ApplicationContext extends
EnvironmentCapable, // 环境感知
ListableBeanFactory, // 可列举的BeanFactory
HierarchicalBeanFactory, // 层次化的BeanFactory
MessageSource, // 国际化消息
ApplicationEventPublisher, // 事件发布
ResourcePatternResolver { // 资源加载
/**
* 获取应用启动时间
*/
long getStartupDate();
/**
* 获取父容器
*/
ApplicationContext getParent();
/**
* 获取AutowireCapableBeanFactory
*/
AutowireCapableBeanFactory getAutowireCapableBeanFactory();
}
看出来了吗? ApplicationContext继承了5个接口!这就是它功能强大的原因!
Q3:常用的实现类
1. ClassPathXmlApplicationContext
通过classpath下的XML配置文件创建:
// beans.xml在src/main/resources下
ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
UserService service = context.getBean("userService", UserService.class);
2. FileSystemXmlApplicationContext
通过文件系统路径的XML配置文件创建:
// 绝对路径或相对路径
ApplicationContext context =
new FileSystemXmlApplicationContext("/path/to/beans.xml");
UserService service = context.getBean("userService", UserService.class);
3. AnnotationConfigApplicationContext(最常用)
通过Java配置类创建:
@Configuration
@ComponentScan("com.example")
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
// 使用
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
UserService service = context.getBean(UserService.class);
4. WebApplicationContext(Web环境)
Spring MVC中的容器:
// 在web.xml中配置
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
// 在代码中获取
WebApplicationContext context =
WebApplicationContextUtils.getWebApplicationContext(servletContext);
🎯 第二问:BeanFactory vs ApplicationContext 七大区别
区别1:Bean的加载时机(最重要!)
BeanFactory:懒加载(Lazy Loading)
// 创建BeanFactory
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("userService",
new RootBeanDefinition(UserService.class));
System.out.println("容器创建完成"); // ← 这时Bean还没创建
// 第一次调用getBean才创建
UserService service = factory.getBean("userService", UserService.class);
System.out.println("Bean创建完成"); // ← 这时才创建
输出:
容器创建完成 ← 快速启动
Bean创建完成 ← 延迟创建
ApplicationContext:饿加载(Eager Loading)
// 创建ApplicationContext
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println("容器创建完成"); // ← 这时所有Bean都创建好了
// 直接获取,不需要创建
UserService service = context.getBean(UserService.class);
System.out.println("Bean已经存在");
输出:
创建UserService... ← 容器启动时就创建
创建OrderService...
创建PaymentService...
容器创建完成 ← 启动稍慢,但Bean都准备好了
Bean已经存在 ← 获取很快
对比表格:
| 维度 | BeanFactory | ApplicationContext |
|---|---|---|
| 加载时机 | 懒加载(第一次getBean) | 饿加载(容器启动时) |
| 启动速度 | 快 ⚡ | 稍慢 🐢 |
| 运行速度 | 慢(需要创建) 🐢 | 快(直接用) ⚡ |
| 内存占用 | 小(按需创建) | 大(全部创建) |
| 错误发现 | 运行时才发现 ❌ | 启动时就发现 ✅ |
| 适用场景 | 资源受限、嵌入式 | 生产环境、Web应用 |
结论:
- 开发/测试: BeanFactory启动快,适合快速迭代
- 生产环境: ApplicationContext更稳定,启动时就能发现错误
区别2:国际化支持
BeanFactory:不支持
// BeanFactory没有国际化接口
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// factory.getMessage(...); ❌ 编译错误,没这个方法
ApplicationContext:支持国际化
准备国际化文件:
# messages_zh_CN.properties
user.welcome=欢迎,{0}!
user.goodbye=再见,{0}!
# messages_en_US.properties
user.welcome=Welcome, {0}!
user.goodbye=Goodbye, {0}!
配置类:
@Configuration
public class I18nConfig {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasename("messages");
source.setDefaultEncoding("UTF-8");
return source;
}
}
使用:
ApplicationContext context =
new AnnotationConfigApplicationContext(I18nConfig.class);
// 中文
String msg = context.getMessage("user.welcome",
new Object[]{"张三"}, Locale.CHINA);
System.out.println(msg); // 输出:欢迎,张三!
// 英文
msg = context.getMessage("user.welcome",
new Object[]{"Tom"}, Locale.US);
System.out.println(msg); // 输出:Welcome, Tom!
应用场景: 多语言应用、国际化网站
区别3:事件发布机制
BeanFactory:不支持
// BeanFactory没有事件发布接口
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// factory.publishEvent(...); ❌ 编译错误
ApplicationContext:支持事件机制
自定义事件:
/**
* 用户注册事件
*/
public class UserRegisterEvent extends ApplicationEvent {
private String username;
private String email;
public UserRegisterEvent(Object source, String username, String email) {
super(source);
this.username = username;
this.email = email;
}
public String getUsername() {
return username;
}
public String getEmail() {
return email;
}
}
事件监听器:
/**
* 发送欢迎邮件监听器
*/
@Component
public class WelcomeEmailListener implements ApplicationListener<UserRegisterEvent> {
@Override
public void onApplicationEvent(UserRegisterEvent event) {
System.out.println("发送欢迎邮件给:" + event.getEmail());
}
}
/**
* 积分奖励监听器
*/
@Component
public class PointsRewardListener implements ApplicationListener<UserRegisterEvent> {
@Override
public void onApplicationEvent(UserRegisterEvent event) {
System.out.println("赠送新人积分给:" + event.getUsername());
}
}
发布事件:
@Service
public class UserService {
@Autowired
private ApplicationContext context;
public void register(String username, String email) {
// 1. 保存用户
System.out.println("保存用户:" + username);
// 2. 发布注册事件
UserRegisterEvent event = new UserRegisterEvent(this, username, email);
context.publishEvent(event);
System.out.println("用户注册完成");
}
}
测试:
public class EventTest {
public static void main(String[] args) {
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
userService.register("张三", "zhangsan@example.com");
}
}
输出:
保存用户:张三
发送欢迎邮件给:zhangsan@example.com
赠送新人积分给:张三
用户注册完成
优势:
- ✅ 解耦:发布者和监听器互不依赖
- ✅ 扩展性:新增监听器不影响现有代码
- ✅ 异步:可以配置异步执行
区别4:资源加载能力
BeanFactory:需要手动加载
// 手动加载资源
Resource resource = new ClassPathResource("config.properties");
Properties props = new Properties();
props.load(resource.getInputStream());
ApplicationContext:强大的资源加载
加载classpath资源:
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
// 单个资源
Resource resource = context.getResource("classpath:config.properties");
System.out.println("文件存在: " + resource.exists());
// 批量加载(支持通配符)
Resource[] resources = context.getResources("classpath*:mapper/*.xml");
System.out.println("找到 " + resources.length + " 个Mapper文件");
加载文件系统资源:
Resource resource = context.getResource("file:/path/to/file.txt");
加载URL资源:
Resource resource = context.getResource("https://example.com/data.json");
加载所有匹配的资源:
// 扫描所有jar包中的resources目录下的sql文件
Resource[] resources = context.getResources("classpath*:sql/*.sql");
for (Resource r : resources) {
System.out.println(r.getFilename());
}
区别5:环境抽象(Environment)
BeanFactory:不支持
// BeanFactory没有环境抽象
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// factory.getEnvironment(); ❌ 没这个方法
ApplicationContext:完整的环境支持
获取配置属性:
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
// 获取Environment
Environment env = context.getEnvironment();
// 读取系统属性
String javaHome = env.getProperty("java.home");
System.out.println("Java Home: " + javaHome);
// 读取环境变量
String path = env.getProperty("PATH");
System.out.println("PATH: " + path);
// 读取application.properties
String appName = env.getProperty("app.name");
System.out.println("App Name: " + appName);
// 检查Profile
boolean isDev = env.acceptsProfiles(Profiles.of("dev"));
System.out.println("开发环境: " + isDev);
Profile功能(环境切换):
@Configuration
public class DataSourceConfig {
@Bean
@Profile("dev") // 开发环境
public DataSource devDataSource() {
return new HikariDataSource(...); // H2内存数据库
}
@Bean
@Profile("prod") // 生产环境
public DataSource prodDataSource() {
return new HikariDataSource(...); // MySQL数据库
}
}
// 激活Profile
System.setProperty("spring.profiles.active", "dev");
ApplicationContext context =
new AnnotationConfigApplicationContext(DataSourceConfig.class);
区别6:BeanPostProcessor自动注册
BeanFactory:需要手动注册
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 注册Bean
factory.registerBeanDefinition("userService",
new RootBeanDefinition(UserService.class));
// 必须手动注册BeanPostProcessor
MyBeanPostProcessor processor = new MyBeanPostProcessor();
factory.addBeanPostProcessor(processor); // ← 手动添加
UserService service = factory.getBean("userService", UserService.class);
ApplicationContext:自动注册
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("处理Bean:" + beanName);
return bean;
}
}
// 使用
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
// BeanPostProcessor自动生效,不需要手动注册!
区别7:BeanFactory处理器(BeanFactoryPostProcessor)
BeanFactory:不支持
// BeanFactory不会处理BeanFactoryPostProcessor
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 即使注册了BeanFactoryPostProcessor,也不会自动执行
ApplicationContext:自动处理
自定义BeanFactoryPostProcessor:
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
System.out.println("=== BeanFactory后置处理器执行 ===");
// 可以修改Bean定义
String[] beanNames = beanFactory.getBeanDefinitionNames();
System.out.println("容器中有 " + beanNames.length + " 个Bean定义");
// 修改某个Bean的定义
if (beanFactory.containsBeanDefinition("userService")) {
BeanDefinition bd = beanFactory.getBeanDefinition("userService");
bd.setScope("prototype"); // 改成原型模式
System.out.println("已将userService改为原型模式");
}
}
}
使用:
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
// BeanFactoryPostProcessor自动执行
// 输出:
// === BeanFactory后置处理器执行 ===
// 容器中有 10 个Bean定义
// 已将userService改为原型模式
📊 七大区别总结表格
| 区别 | BeanFactory | ApplicationContext | 重要性 |
|---|---|---|---|
| 1. 加载时机 | 懒加载 | 饿加载 | ⭐⭐⭐⭐⭐ |
| 2. 国际化 | ❌ 不支持 | ✅ 支持 | ⭐⭐⭐ |
| 3. 事件机制 | ❌ 不支持 | ✅ 支持 | ⭐⭐⭐⭐ |
| 4. 资源加载 | 基础 | 强大 | ⭐⭐⭐ |
| 5. 环境抽象 | ❌ 不支持 | ✅ 支持 | ⭐⭐⭐⭐ |
| 6. BeanPostProcessor | 手动注册 | 自动注册 | ⭐⭐⭐⭐ |
| 7. BeanFactoryPostProcessor | ❌ 不支持 | ✅ 支持 | ⭐⭐⭐⭐ |
🔍 第三问:ApplicationContext启动流程源码分析
核心方法:refresh()
位置: org.springframework.context.support.AbstractApplicationContext
源码(简化版):
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备刷新上下文
prepareRefresh();
// 2. 获取BeanFactory(核心!)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 准备BeanFactory
prepareBeanFactory(beanFactory);
try {
// 4. BeanFactory后置处理
postProcessBeanFactory(beanFactory);
// 5. 执行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 7. 初始化国际化资源
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 刷新(模板方法,子类可扩展)
onRefresh();
// 10. 注册事件监听器
registerListeners();
// 11. 实例化所有单例Bean(核心!)
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新
finishRefresh();
}
catch (BeansException ex) {
// 销毁已创建的Bean
destroyBeans();
// 取消刷新
cancelRefresh(ex);
throw ex;
}
finally {
// 清理缓存
resetCommonCaches();
}
}
}
流程图
ApplicationContext启动流程
│
├─ 1. prepareRefresh()
│ └─ 设置启动时间、激活标志
│
├─ 2. obtainFreshBeanFactory() ← 核心
│ ├─ 创建BeanFactory
│ ├─ 加载Bean定义
│ └─ 返回BeanFactory
│
├─ 3. prepareBeanFactory()
│ ├─ 设置类加载器
│ ├─ 添加BeanPostProcessor
│ └─ 注册默认环境Bean
│
├─ 4-5. 执行BeanFactoryPostProcessor
│ └─ 修改Bean定义
│
├─ 6. 注册BeanPostProcessor
│ └─ 注册所有BeanPostProcessor
│
├─ 7-8-10. 初始化国际化、事件机制
│
├─ 11. finishBeanFactoryInitialization() ← 核心
│ ├─ 实例化所有单例Bean
│ ├─ 依赖注入
│ └─ 初始化回调
│
└─ 12. finishRefresh()
├─ 发布ContextRefreshedEvent
└─ 启动完成
关键步骤详解
步骤2:obtainFreshBeanFactory()
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 刷新BeanFactory(子类实现)
refreshBeanFactory();
// 返回BeanFactory
return getBeanFactory();
}
// AnnotationConfigApplicationContext的实现
@Override
protected final void refreshBeanFactory() {
// 创建DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置序列化ID
beanFactory.setSerializationId(getId());
// 定制BeanFactory
customizeBeanFactory(beanFactory);
// 加载Bean定义(扫描@Component等)
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
关键: ApplicationContext内部使用的就是DefaultListableBeanFactory!
步骤11:finishBeanFactoryInitialization()
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 初始化类型转换服务
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// 冻结配置
beanFactory.freezeConfiguration();
// 实例化所有剩余的单例Bean(核心!)
beanFactory.preInstantiateSingletons();
}
preInstantiateSingletons()源码:
@Override
public void preInstantiateSingletons() throws BeansException {
// 获取所有Bean名称
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 遍历所有Bean
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 不是抽象、是单例、不是懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// FactoryBean特殊处理
// ...
}
else {
// 普通Bean:调用getBean创建
getBean(beanName); // ← 这里触发Bean创建!
}
}
}
// 触发所有单例Bean的初始化后回调
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton =
(SmartInitializingSingleton) singletonInstance;
smartSingleton.afterSingletonsInstantiated();
}
}
}
看到了吗?
- ApplicationContext启动时会遍历所有Bean定义
- 调用
getBean()创建所有单例Bean - 这就是"饿加载"的实现!
💻 第四问:实战对比演示
准备测试Bean
@Component
public class UserDao {
public UserDao() {
System.out.println(">>> UserDao被创建,时间:" +
System.currentTimeMillis());
}
}
@Component
public class UserService {
@Autowired
private UserDao userDao;
public UserService() {
System.out.println(">>> UserService被创建,时间:" +
System.currentTimeMillis());
}
public String getUser(Long id) {
return "User-" + id;
}
}
@Component
public class OrderService {
@Autowired
private UserService userService;
public OrderService() {
System.out.println(">>> OrderService被创建,时间:" +
System.currentTimeMillis());
}
public String createOrder(Long userId) {
return "Order for " + userService.getUser(userId);
}
}
测试1:BeanFactory懒加载
public class BeanFactoryTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
System.out.println("===== BeanFactory测试 =====\n");
// 1. 创建BeanFactory
System.out.println("--- 创建BeanFactory ---");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 2. 注册Bean定义
factory.registerBeanDefinition("userDao",
new RootBeanDefinition(UserDao.class));
factory.registerBeanDefinition("userService",
new RootBeanDefinition(UserService.class));
factory.registerBeanDefinition("orderService",
new RootBeanDefinition(OrderService.class));
long end1 = System.currentTimeMillis();
System.out.println("容器创建完成,耗时:" + (end1 - start) + "ms\n");
// 3. 第一次getBean
System.out.println("--- 第一次获取OrderService ---");
OrderService orderService = factory.getBean("orderService", OrderService.class);
long end2 = System.currentTimeMillis();
System.out.println("获取Bean耗时:" + (end2 - end1) + "ms\n");
// 4. 使用Bean
System.out.println("--- 使用Bean ---");
String result = orderService.createOrder(123L);
System.out.println("结果:" + result);
System.out.println("\n总耗时:" + (System.currentTimeMillis() - start) + "ms");
}
}
输出:
===== BeanFactory测试 =====
--- 创建BeanFactory ---
容器创建完成,耗时:2ms
--- 第一次获取OrderService ---
>>> OrderService被创建,时间:1705737001234
>>> UserService被创建,时间:1705737001235
>>> UserDao被创建,时间:1705737001236
获取Bean耗时:15ms
--- 使用Bean ---
结果:Order for User-123
总耗时:18ms
分析:
- ✅ 容器启动快(2ms)
- ❌ 第一次使用慢(15ms创建Bean)
- Bean在第一次getBean时才创建
测试2:ApplicationContext饿加载
public class ApplicationContextTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
System.out.println("===== ApplicationContext测试 =====\n");
// 1. 创建ApplicationContext
System.out.println("--- 创建ApplicationContext ---");
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
long end1 = System.currentTimeMillis();
System.out.println("容器创建完成,耗时:" + (end1 - start) + "ms\n");
// 2. 获取Bean(已经创建好了)
System.out.println("--- 获取OrderService ---");
OrderService orderService = context.getBean(OrderService.class);
long end2 = System.currentTimeMillis();
System.out.println("获取Bean耗时:" + (end2 - end1) + "ms\n");
// 3. 使用Bean
System.out.println("--- 使用Bean ---");
String result = orderService.createOrder(123L);
System.out.println("结果:" + result);
System.out.println("\n总耗时:" + (System.currentTimeMillis() - start) + "ms");
}
}
输出:
===== ApplicationContext测试 =====
--- 创建ApplicationContext ---
>>> UserDao被创建,时间:1705737101234
>>> UserService被创建,时间:1705737101235
>>> OrderService被创建,时间:1705737101236
容器创建完成,耗时:156ms
--- 获取OrderService ---
获取Bean耗时:0ms
--- 使用Bean ---
结果:Order for User-123
总耗时:158ms
分析:
- ❌ 容器启动慢(156ms,包含创建Bean)
- ✅ 获取Bean快(0ms,直接从缓存取)
- Bean在容器启动时就创建好了
对比总结
| 维度 | BeanFactory | ApplicationContext |
|---|---|---|
| 容器启动 | 2ms ⚡ | 156ms 🐢 |
| 首次获取Bean | 15ms 🐢 | 0ms ⚡ |
| Bean创建时机 | 第一次getBean | 容器启动时 |
| 错误发现 | 运行时 | 启动时 ✅ |
| 总体性能 | 启动快,运行慢 | 启动慢,运行快 ✅ |
结论:
- 开发环境: 两者都可以,看个人喜好
- 生产环境: 强烈推荐ApplicationContext!
🎯 第五问:如何选择容器?
决策树
你的应用场景是?
│
├─ 资源极度受限(嵌入式设备)
│ └─ 选择:BeanFactory
│
├─ 快速原型开发、单元测试
│ └─ 选择:BeanFactory 或 ApplicationContext
│
├─ Web应用
│ └─ 选择:ApplicationContext(强制)
│
├─ 需要国际化
│ └─ 选择:ApplicationContext
│
├─ 需要事件机制
│ └─ 选择:ApplicationContext
│
├─ 生产环境
│ └─ 选择:ApplicationContext(强烈推荐)
│
└─ 不确定
└─ 选择:ApplicationContext(默认选择)
官方建议
Spring官方文档说明:
You should use an ApplicationContext unless you have a good reason for not doing so.
翻译:除非你有充分的理由,否则应该使用ApplicationContext。
什么是"充分的理由"?
- 运行在资源极度受限的环境(如嵌入式设备)
- 应用只需要最基础的IoC功能
- 对启动时间有极致要求(毫秒级)
99%的情况应该用ApplicationContext!
💡 知识点总结
本篇你学到了什么?
✅ ApplicationContext的定位
- 继承BeanFactory,功能更强
- 继承5个接口,提供额外功能
✅ 七大核心区别
- 加载时机:懒加载 vs 饿加载 ⭐⭐⭐⭐⭐
- 国际化:不支持 vs 支持
- 事件机制:不支持 vs 支持
- 资源加载:基础 vs 强大
- 环境抽象:不支持 vs 支持
- BeanPostProcessor:手动 vs 自动
- BeanFactoryPostProcessor:不支持 vs 支持
✅ ApplicationContext启动流程
- 12个关键步骤
- refresh()方法是核心
- preInstantiateSingletons()实现饿加载
✅ 实战对比
- BeanFactory:启动快(2ms),运行慢
- ApplicationContext:启动慢(156ms),运行快
✅ 选择建议
- 99%场景用ApplicationContext
- 生产环境必须用ApplicationContext
🤔 思考题
问题1: ApplicationContext启动时,所有Bean都会创建吗?有没有例外?
提示: 想想@Lazy注解、prototype作用域
问题2: 如果Bean创建过程中抛异常,ApplicationContext会怎样?BeanFactory呢?
提示: 启动时失败 vs 运行时失败
问题3: Bean的完整生命周期有哪些阶段?BeanPostProcessor在哪个阶段执行?
提示: 下一篇详细讲解11个步骤!
📢 下期预告(系列完结篇)
《IoC容器深度解析(三):Bean生命周期完整流程,11步骤深度剖析!》
下一篇我们将:
- 深入Bean生命周期的11个完整步骤
- 详解所有BeanPostProcessor的执行时机
- 源码级分析AbstractAutowireCapableBeanFactory
- 手写代码验证每个生命周期回调
- 实战:自定义BeanPostProcessor
- 解析Spring如何解决循环依赖(三级缓存)
系列完结篇,干货满满! 🚀
💬 互动时间
你在生产环境中遇到过容器启动慢的问题吗?
对ApplicationContext的7大区别,哪个最让你印象深刻?
还有哪些关于容器的疑问?
欢迎评论区讨论!💭
觉得有帮助?三连支持: 👍 点赞 | ⭐ 收藏 | 🔄 转发
看完这篇,BeanFactory和ApplicationContext不再混淆! ✨
下一篇见(完结篇)! 👋