hexon
发布于 2026-07-05 / 4 阅读
0

扩展:Spring 容器生命周期管理深度解析

本文深入剖析 Spring IoC 容器中 LifecycleSmartLifecycle 的设计原理、启动机制以及 refresh()start() 的关系,帮助理解 Spring 容器的完整生命周期控制流程。


目录

  • 一、容器启动核心流程

  • 二、refresh() 启动了什么?

  • 三、LifecycleSmartLifecycle

    • 3.1 Lifecycle 接口

    • 3.2 SmartLifecycle 接口

    • 3.3 对比总结

  • 四、DefaultLifecycleProcessor 源码解析

    • 4.1 核心成员变量

    • 4.2 startBeans(boolean autoStartupOnly)

    • 4.3 isAutoStartupCandidate() 判断逻辑

    • 4.4 stoppedBeans 的作用

  • 五、refresh() vs start() 调用顺序

    • 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。


三、LifecycleSmartLifecycle

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 对比总结

特性

Lifecycle

SmartLifecycle

refresh() 自动启动

❌ 否

✅ 是(isAutoStartup=true

context.start() 手动启动

✅ 是

✅ 是

启动顺序控制

❌ 否

getPhase()

异步优雅停止

❌ 否

stop(Runnable)

适用场景

需显式控制的组件

需自动启动的组件(消息监听、定时任务等)


四、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()));
}

判断规则

场景

stoppedBeans 状态

返回值

含义

正常刷新容器

null

bean instanceof SmartLifecycle && isAutoStartup()

只识别 SmartLifecycle

手动 start() 调用

被置为 null

true(所有 Bean)

全部启动

手动 stopBean()

非空(包含 Bean 名)

包含则 true,否则 false

只启动被停止的 Bean

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;
}

核心差异

调用入口

调用方法

autoStartupOnly 参数

启动范围

refresh()finishRefresh()

onRefresh()startBeans(true)

true

SmartLifecycleisAutoStartup=true

手动 context.start()

start()startBeans(false)

false

所有 Lifecycle + SmartLifecycle

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 context

5.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() 之前

业务层面的优雅停止(关闭连接、保存状态)

❌ 否

close()

应用关闭时

容器层面的销毁(释放内存、销毁 Bean)

手动(或 Hook)

如果忘记调用 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; }
}


八、总结

核心要点速记

概念

说明

Lifecycle

基础生命周期接口,不会自动启动

SmartLifecycle

扩展接口,isAutoStartup=true 时在 refresh() 自动启动

refresh()

容器初始化,调用 startBeans(true)(仅启动 SmartLifecycle

context.start()

手动启动,调用 startBeans(false)(启动全部 Lifecycle

context.stop()

手动停止,必须在 close() 之前调用

context.close()

容器销毁,不调用 Lifecycle.stop()

stoppedBeans

记录手动停止的 Bean,支持细粒度控制

调用顺序铁律

refresh() → start() → 业务逻辑 → stop() → close()
   ↑          ↑                    ↑         ↑
 初始化    手动启动            优雅停止   容器销毁

设计哲学

Spring 通过 autoStartupOnly 这个布尔值巧妙地实现了自动引导手动控制的分离:

  1. 自动SmartLifecycle 在容器启动时就绪,保证关键组件自动运行

  2. 手动:普通 Lifecycle 由开发者决定启动时机,保证灵活性

  3. 优雅stop()close() 分离,确保资源正确释放