前言
在使用 Spring 开发时,我们都知道,所有 bean 都交给 Spring 容器来统一管理,其中包括每一个 bean 的加载和初始化。有时候我们需要:在 Spring 加载和初始化所有 bean 后,接着执行一些任务或者启动需要的异步服务,当我们遇上这样的情况,有什么方法可以解决?
定时任务?怎么去控制这个时间点?- 现在基于Spring的应用非常多,Spring有没提供相应的机制?
Spring 给我们提供了回调的机制——Lifecycle,在容器启动后、停止前进行调用。
一、启动 / 关闭 回调机制
1. Lifecycle 接口概述
Lifecycle 定义启动/停止生命周期控制方法的通用接口。这种情况的典型用例是控制异步处理。可由组件(通常是 Spring 上下文中定义的 bean)和容器(通常是 Spring 的 ApplicationContext 本身)实现。
public interface Lifecycle {
/**
* 启动当前组件
* <p>如果组件已经在运行,不应该抛出异常
* <p>在容器的情况下,这会将 开始信号 传播到应用的所有组件中去。
*/
void start();
/**
* 通常以同步方式停止该组件,当该方法执行完成后,该组件会被完全停止。
*/
void stop();
/**
* 检查此组件是否正在运行。
* 1. 只有该方法返回false时,start方法才会被执行。
* 2. 只有该方法返回true时,stop(Runnable callback)或stop()方法才会被执行。
*/
boolean isRunning();
}
Lifecycle 定义Spring 容器对象的生命周期,任何 Spring 管理对象都可以实现该接口。然后,当 ApplicationContext 本身接收启动和停止信号(例如在运行时停止/重启场景)时,Spring 容器将在容器上下文中找出所有实现了 Lifecycle 及其子类接口的类,并一一调用它们实现的类。Spring是通过委托给生命周期处理器 LifecycleProcessor 来实现这一点的。
注:Lifecycle 生命周期的不足
常规的 Lifecycle 接口只是在容器上下文显式的调用 start() / stop() 方法时,才会去回调 Lifecycle 的实现类的 start stop 方法逻辑。并不意味着在上下文刷新时自动启动。若想在 Spring 容器没有显示调用 start 和 destory 等方法时,我们也需要做到生命周期回调,可以考虑 SmartLifecyle
2. SmartLifecycle 接口概述
SmartLifecycle 是 Lifecycle 接口的扩展,用于那些需要在 ApplicationContext 按特定顺序刷新和/或关闭时启动的对象。 isAutoStartup() 返回值指示是否应在上下文刷新时启动此对象。回调方法 stop(Runnable) 对于具有异步关闭过程的对象很有用。
此接口的任何实现都必须在关闭完成时调用回调的 run() 方法,以避免整个 ApplicationContext 关闭中出现不必要的延迟。
此接口扩展了 Phased,getPhase() 方法的返回值指示应该启动和停止此 Lifecycle 组件的阶段。启动过程以最低相位值开始,以最高相位值结束(Integer.MIN_VALUE最低,Integer.MAX_VALUE最高)。关闭过程将应用相反的顺序。具有相同值的任何组件将在同一阶段中任意排序。
public interface SmartLifecycle extends Lifecycle, Phased {
int DEFAULT_PHASE = Integer.MAX_VALUE;
/**
* 如果该`Lifecycle`类所在的上下文在调用`refresh`时,希望能够自己自动进行回调,则返回`true`* ,
* false的值表明组件打算通过显式的start()调用来启动,类似于普通的Lifecycle实现。
*/
default boolean isAutoStartup() {
return true;
}
default void stop(Runnable callback) {
stop();
callback.run();
}
default int getPhase() {
return DEFAULT_PHASE;
}
}
二、源码分析
org.springframework.context.support.AbstractApplicationContext 代码片段
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...
try {
...
// Last step: publish corresponding event.
finishRefresh();
}
...
}
}
protected void finishRefresh() {
...
//初始化 lifecycle 的处理器(默认是DefaultLifecycleProcessor)
initLifecycleProcessor();
// 将刷新信号传播到 lifecycle 的处理器
getLifecycleProcessor().onRefresh();
...
}
org.springframework.context.support.DefaultLifecycleProcessor 代码片段
@Override
public void onRefresh() {
startBeans(true);
this.running = true;
}
private void startBeans(boolean autoStartupOnly) {
//获取Lifecycle接口实现的bean
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
//筛选出SmartLifecycle 实例,并设置自动启动的,按执行顺序分组
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
int phase = getPhase(bean);
LifecycleGroup group = phases.get(phase);
if (group == null) {
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
phases.put(phase, group);
}
group.add(beanName, bean);
}
});
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
//按执行阶段排序:从小到大
Collections.sort(keys);
for (Integer key : keys) {
phases.get(key).start(); //启动
}
}
}
private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
// 移除已经执行过start方法的bean,因为下面依赖原因,避免重复调用
Lifecycle bean = lifecycleBeans.remove(beanName);
if (bean != null && bean != this) {
// 依赖的bean也是Lifecycle先执行它的start方法
String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
for (String dependency : dependenciesForBean) {
doStart(lifecycleBeans, dependency, autoStartupOnly);
}
// 需要是非运行状态且是isAutoStartup
if (!bean.isRunning() && (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {
...
try {
bean.start(); //启动
}
...
}
}
}