本文深入剖析 Spring IoC 容器中
Lifecycle与SmartLifecycle的设计原理、启动机制以及refresh()与start()的关系,帮助理解 Spring 容器的完整生命周期控制流程。
目录
一、容器启动核心流程
二、
refresh()启动了什么?三、
Lifecycle与SmartLifecycle3.1 Lifecycle 接口
3.2 SmartLifecycle 接口
3.3 对比总结
四、
DefaultLifecycleProcessor源码解析4.1 核心成员变量
4.2
startBeans(boolean autoStartupOnly)4.3
isAutoStartupCandidate()判断逻辑4.4
stoppedBeans的作用
五、
refresh()vsstart()调用顺序5.1 源码证据
5.2 错误示例
5.3 完整生命周期时序图
六、
stop()与close()的区别七、最佳实践
八、总结
一、容器启动核心流程
Spring 容器的启动入口是 AbstractApplicationContext.refresh() 方法,它定义了 IoC 容器的初始化过程:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备刷新
prepareRefresh();
// 2. 获取 BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 准备 BeanFactory
prepareBeanFactory(beanFactory);
// 4. 允许子类后置处理
postProcessBeanFactory(beanFactory);
// 5. 调用 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册 BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 7. 初始化消息源
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 初始化特殊的 Bean(由子类实现)
onRefresh();
// 10. 注册事件监听器
registerListeners();
// 11. 完成 BeanFactory 的初始化,实例化所有非懒加载的单例 Bean
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新,发布 ContextRefreshedEvent 事件
finishRefresh();
}
}其中 finishRefresh() 方法会触发生命周期组件的启动,而 start() 方法则需要手动调用。
二、refresh() 启动了什么?
finishRefresh() 方法的实现:
protected void finishRefresh() {
// 初始化生命周期处理器
initLifecycleProcessor();
// 通知生命周期处理器刷新
getLifecycleProcessor().onRefresh();
// 发布 ContextRefreshedEvent 事件
publishEvent(new ContextRefreshedEvent(this));
// ...
}DefaultLifecycleProcessor.onRefresh() 的实现:
@Override
public void onRefresh() {
startBeans(true); // ← 注意参数是 true
this.running = true;
}关键点:onRefresh() 调用的是 startBeans(true),意味着只启动满足条件的一部分 Bean。
三、Lifecycle 与 SmartLifecycle
3.1 Lifecycle 接口
最基本的生命周期控制接口,定义了启动和停止的契约:
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}特点:
所有实现类不会在容器
refresh()时自动启动需要通过
ConfigurableApplicationContext.start()手动触发常用于需要显式控制运行状态的组件
3.2 SmartLifecycle 接口
Lifecycle 的扩展接口,增加了自动启动和优先级控制:
public interface SmartLifecycle extends Lifecycle, Phased {
// 是否在容器刷新时自动启动
default boolean isAutoStartup() {
return true;
}
// 启动优先级(数值越小优先级越高)
default int getPhase() {
return 0;
}
// 优雅停止时的回调
default void stop(Runnable callback) {
stop();
callback.run();
}
}特点:
若
isAutoStartup()返回true,在容器refresh()时会自动启动支持
getPhase()控制启动/停止顺序支持异步优雅停止(
stop(Runnable callback))
3.3 对比总结
四、DefaultLifecycleProcessor 源码解析
4.1 核心成员变量
public class DefaultLifecycleProcessor implements LifecycleProcessor {
// 所有 Lifecycle Bean 的缓存
private final Map<String, Lifecycle> lifecycleBeans = new LinkedHashMap<>();
// 被手动停止的 Bean 名称集合
private final Set<String> stoppedBeans = new LinkedHashSet<>();
private volatile boolean running;
// ...
}4.2 startBeans(boolean autoStartupOnly)
这是理解 Spring 生命周期行为差异的核心方法:
private void startBeans(boolean autoStartupOnly) {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new TreeMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
// 关键判断:是否将当前 Bean 加入启动队列
if (!autoStartupOnly || isAutoStartupCandidate(beanName, bean)) {
int startupPhase = getPhase(bean);
phases.computeIfAbsent(startupPhase,
phase -> new LifecycleGroup(phase, lifecycleBeans, autoStartupOnly))
.add(beanName, bean);
}
});
if (!phases.isEmpty()) {
phases.values().forEach(LifecycleGroup::start);
}
}4.3 isAutoStartupCandidate() 判断逻辑
private boolean isAutoStartupCandidate(String beanName, Lifecycle bean) {
Set<String> stoppedBeans = this.stoppedBeans;
return (stoppedBeans != null ? stoppedBeans.contains(beanName) :
(bean instanceof SmartLifecycle smartLifecycle && smartLifecycle.isAutoStartup()));
}判断规则:
4.4 stoppedBeans 的作用
stoppedBeans 用于记录被手动停止的 Bean 名称,实现细粒度的生命周期控制:
@Override
public void stop(Runnable callback) {
// 手动停止时,记录所有 Bean
this.stoppedBeans.addAll(this.lifecycleBeans.keySet());
// ... 停止逻辑
}
public void stopBean(String beanName) {
Lifecycle bean = this.lifecycleBeans.get(beanName);
if (bean != null && isRunning(beanName)) {
bean.stop();
this.stoppedBeans.add(beanName); // 记录到停止集合
}
}设计意图:
支持"停止-重新启动"的幂等操作
区分"从未启动"和"已停止"两种状态
避免重复启动已经停止的 Bean
五、refresh() vs start() 调用顺序
5.1 源码证据
AbstractApplicationContext.start() 的实现:
@Override
public void start() {
getLifecycleProcessor().start();
publishEvent(new ContextStartedEvent(this));
}DefaultLifecycleProcessor.start() 的实现:
@Override
public void start() {
this.stoppedBeans = null; // 重置停止标记
startBeans(false); // ← 参数是 false,启动全部
this.running = true;
}核心差异:
5.2 错误示例
// ❌ 错误:先调用 start(),再 refresh()
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.start(); // 抛出 IllegalStateException
context.refresh();异常信息:
Exception in thread "main" java.lang.IllegalStateException:
LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context5.3 完整生命周期时序图
时间轴 ────────────────────────────────────────────────────────────────►
1. new 容器实例
│
▼
2. refresh()
├── 加载 Bean 定义
├── 实例化 Bean
├── 注入依赖
├── 初始化 Bean
├── finishRefresh()
│ └── lifecycleProcessor.onRefresh()
│ └── startBeans(true) ← 自动启动 SmartLifecycle
│
▼ 容器就绪(但普通 Lifecycle 未启动)
│
3. context.start() ← 手动启动
└── lifecycleProcessor.start()
└── startBeans(false) ← 启动所有 Lifecycle + SmartLifecycle
│
▼ 所有 Lifecycle 组件运行中
│
4. 执行业务逻辑
│
▼
5. context.stop() ← 手动停止
└── lifecycleProcessor.stop()
└── stopBeans()
│
▼ 所有 Lifecycle 组件停止
│
6. context.close()
└── 销毁所有 Bean,释放资源六、stop() 与 close() 的区别
查看 AbstractApplicationContext.close() 的源码:
@Override
public void close() {
synchronized (this.startupShutdownMonitor) {
doClose();
}
}
protected void doClose() {
// 发布 ContextClosedEvent 事件
publishEvent(new ContextClosedEvent(this));
// 销毁所有单例 Bean(直接释放对象)
destroyBeans();
// 关闭 BeanFactory
closeBeanFactory();
// 清空上下文状态
clearCache();
}关键发现:close() 方法完全没有调用 lifecycleProcessor.stop()!
如果忘记调用 stop() 直接 close():
Lifecycle.stop()不会被调用资源(线程、连接)可能未释放
非守护线程可能阻止 JVM 退出
可能导致内存泄漏
七、最佳实践
方式一:手动管理(适用于命令行/独立应用)
public class BestPracticeApp {
public static void main(String[] args) {
ConfigurableApplicationContext context = null;
try {
context = new AnnotationConfigApplicationContext(AppConfig.class);
context.refresh();
context.start();
// 执行业务逻辑...
} finally {
if (context != null) {
context.stop(); // 先优雅停止
context.close(); // 再销毁容器
}
}
}
}方式二:使用 Shutdown Hook(适用于 Web 应用/后台服务)
public class ShutdownHookApp {
public static void main(String[] args) {
ConfigurableApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
context.refresh();
context.start();
// 注册 JVM 关闭钩子(自动调用 stop + close)
context.registerShutdownHook();
// 保持主线程运行
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}方式三:实现 DisposableBean 接口(综合管理)
@Component
public class MyLifecycleBean implements SmartLifecycle, DisposableBean {
private boolean running = false;
private Thread workerThread;
@Override
public void start() {
if (!running) {
System.out.println("启动工作线程...");
workerThread = new Thread(this::work);
workerThread.start();
running = true;
}
}
@Override
public void stop() {
if (running) {
System.out.println("优雅停止工作线程...");
running = false;
if (workerThread != null) {
workerThread.interrupt();
try {
workerThread.join(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
@Override
public void destroy() throws Exception {
// 防御性二次停止
if (running) {
stop();
}
}
private void work() {
while (running) {
try {
// 业务逻辑
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
@Override
public boolean isRunning() { return running; }
@Override
public boolean isAutoStartup() { return true; }
@Override
public int getPhase() { return 0; }
}八、总结
核心要点速记
调用顺序铁律
refresh() → start() → 业务逻辑 → stop() → close()
↑ ↑ ↑ ↑
初始化 手动启动 优雅停止 容器销毁设计哲学
Spring 通过 autoStartupOnly 这个布尔值巧妙地实现了自动引导和手动控制的分离:
自动:
SmartLifecycle在容器启动时就绪,保证关键组件自动运行手动:普通
Lifecycle由开发者决定启动时机,保证灵活性优雅:
stop()与close()分离,确保资源正确释放