前言

        在使用 Spring 开发时,我们都知道,所有 bean 都交给 Spring 容器来统一管理,其中包括每一个 bean 的加载和初始化。有时候我们需要:在 Spring 加载和初始化所有 bean 后,接着执行一些任务或者启动需要的异步服务,当我们遇上这样的情况,有什么方法可以解决?

  1. 定时任务?怎么去控制这个时间点?
  2. 现在基于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(); //启动
			}
			...
		}
	}
}