1、LifeCycle接口概述
LifeCycle定义启动/停止生命周期控制方法的通用接口。这种情况的典型用例是控制异步处理。可以由两个组件(通常是Spring上下文中定义的Spring bean)和容器(通常是Spring ApplicationContext本身)实现。容器将开始/停止信号传播到每个容器内应用的所有组件。可用于通过JMX进行直接调用或管理操作,org.springframework.jmx.export.MBeanExporter通常使用org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler定义,从而限制活动控制组件对Lifecycle接口的可见性。
请注意,仅在顶级单例bean上支持当前的Lifecycle接口。在任何其他组件上,Lifecycle接口将保持未被检测到,因此将被忽略。另请注意,扩展的SmartLifecycle接口提供了与应用程序上下文的启动和关闭阶段的复杂集成。
2、SmartLifecycle接口
2.1、概述
SmartLifecycle是Lifecycle接口的扩展,用于那些需要在ApplicationContext按特定顺序刷新和/或关闭时启动的对象。 isAutoStartup()返回值指示是否应在上下文刷新时启动此对象。回调方法stop(Runnable)对于具有异步关闭过程的对象很有用。此接口的任何实现都必须在关闭完成时调用回调的run()方法,以避免整个ApplicationContext关闭中出现不必要的延迟。
此接口扩展了Phased,getPhase()方法的返回值指示应该启动和停止此Lifecycle组件的阶段。启动过程以最低相位值开始,以最高相位值结束(Integer.MIN_VALUE最低,Integer.MAX_VALUE最高)。关闭过程将应用相反的顺序。具有相同值的任何组件将在同一阶段中任意排序。
示例:如果组件B依赖于已经启动的组件A,则组件A的相位值应低于组件B.在关闭过程中,组件B将在组件A之前停止。
任何明确的“依赖”关系都优先于阶段顺序,因此依赖bean始终在其依赖之后启动,并始终在其依赖之前停止。
上下文中未实现SmartLifecycle的任何生命周期组件都将被视为具有0的阶段值。这样,SmartLifecycle实现可以在这些生命周期组件之前开始,如果它具有负相位值,或者可以在那些之后开始组件,如果它具有正相位值。
请注意,由于SmartLifecycle中的自动启动支持,SmartLifecycle bean实例通常会在应用程序上下文启动时初始化。因此,bean定义lazy-init标志对SmartLifecycle bean的实际影响非常有限。
2.2、类图
2.3、方法说明
方法 | 描述 |
---|---|
方法 | 描述 |
start() | bean初始化完毕后,该方法会被执行,对于容器,这会将启动信号传播到所有适用的组件。 |
stop() | 通常以同步方式停止此组件,以便在返回此方法时组件完全停止。当需要异步停止行为时,请考虑实现SmartLifecycle及其stop(Runnable)变体。 |
isRunning() | 检查此组件当前是否正在运行。对于容器,仅当应用的所有组件当前正在运行时,才会返回true。 |
getPhase() | 返回此生命周期对象应运行的阶段。默认实现返回Integer.MAX_VALUE,以便在常规生命周期实现后执行停止回调。 |
isAutoStartup() | 如果随ApplicationContext刷新时容器自动启动此Lifecycle组件时,则返回true。值false表示该组件旨在通过显式的start()调用启动,类似于普通的Lifecycle实现。默认实现返回true。 |
stop(Runnable) | spring容器发现当前对象实现了SmartLifecycle,就调用stop(Runnable),如果只是实现了Lifecycle,就调用stop() |
3、LifecycleProcessor
用于在ApplicationContext中处理Lifecycle bean的策略接口。LifecycleProcessor接口有两个方法,下图显示了其调用流程。
前者在ApplicationContext刷新时调用,后再在ApplicationContext关闭时调用。
4、源码分析
4.1、容器启动流程
在Spring容器启动的时候会调用ApplicationContext的refresh方法,此方法在最后一个步骤是调用finishRefresh方法。
这个方法中首先会实例化一个LifecycleProcessor:先从容器中找一个名为lifecycleProcessor的LifecycleProcessor否则使用DefaultLifecycleProcessor。下面是DefaultLifecycleProcessor的实现。
@Override
public void onRefresh() {
startBeans(true);
this.running = true;
}
private void startBeans(boolean autoStartupOnly) {
// 单例非懒加载bean
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
// 默认autoStartupOnly=true,因此只能筛选出是SmartLifecycle.isAutoStartup()=true的bean
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
int phase = getPhase(bean);
// 相同phases一组
LifecycleGroup group = phases.get(phase);
if (group == null) {
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
phases.put(phase, group);
}
// 向group的members添加beanName, bean
group.add(beanName, bean);
}
});
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
// phases从小到大
Collections.sort(keys);
for (Integer key : keys) {
// 同属一个组的Lifecycle一起启动
phases.get(key).start();
}
}
}
上面代码是从容器中选出非懒加载单例的Lifecycle,DefaultLifecycleProcessor只筛选出SmartLifecycle.isAutoStartup()=true的bean,把相同phase的bean封装成一个组LifecycleGroup,这些组按照phase从小到大依次调用start方法。下面是其实现。
public void start() {
if (this.members.isEmpty()) {
return;
}
if (logger.isDebugEnabled()) {
logger.debug("Starting beans in phase " + this.phase);
}
Collections.sort(this.members);
for (LifecycleGroupMember member : this.members) {
doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
}
}
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())) {
if (logger.isTraceEnabled()) {
logger.trace("Starting bean '" + beanName + "' of type [" + bean.getClass().getName() + "]");
}
try {
bean.start();
}
catch (Throwable ex) {
throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex);
}
if (logger.isDebugEnabled()) {
logger.debug("Successfully started bean '" + beanName + "'");
}
}
}
}
4.2、容器关闭流程
当Spring容器启动失败的时候会调用close()方法,当然主动调用也可以。
@Override
public void close() {
synchronized (this.startupShutdownMonitor) {
doClose();
// If we registered a JVM shutdown hook, we don't need it anymore now:
// We've already explicitly closed the context.
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
// ignore - VM is already shutting down
}
}
}
}
close方法会调用doClose方法,这个方法中会调用lifecycleProcessor.onClose();
下面是DefaultLifecycleProcessor的实现代码:
@Override
public void onClose() {
stopBeans();
this.running = false;
}
private void stopBeans() {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
int shutdownPhase = getPhase(bean);
LifecycleGroup group = phases.get(shutdownPhase);
if (group == null) {
group = new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false);
phases.put(shutdownPhase, group);
}
group.add(beanName, bean);
});
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
keys.sort(Collections.reverseOrder());
for (Integer key : keys) {
phases.get(key).stop();
}
}
}