1. 源码分析
源码位置:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...
//初始化非延迟加载的bean
finishBeanFactoryInitialization(beanFactory);
//最后一步:发布相应的事件(执行Lifecycle生命周期)。
finishRefresh();
}
}
bean的创建时在finishBeanFactoryInitialization(beanFactory);
方法。该方法中也有bean的生命周期的回调方法。SpringBoot2.x基础篇—Bean的生命周期方法(与容器耦合)
而实现了Lifecycle接口的bean,将会在finishRefresh();
方法中执行生命周期方法。(此时所有的bean均初始化完毕即Spring初始化完成,与Spring容器的创建解耦)。
2. 接口分析
常规的LifeCycle接口只是在容器上下文显式的调用start()/stop()方法时,才会去回调LifeCycle的实现类的start stop方法逻辑。并不意味着在上下文刷新时自动启动。
public interface Lifecycle {
/**
* 启动当前组件
* <p>如果组件已经在运行,不应该抛出异常
* <p>在容器的情况下,这会将开始信号 传播到应用的所有组件中去。
*/
void start();
/**
* (1)通常以同步方式停止该组件,当该方法执行完成后,该组件会被完全停止。当需要异步停止行为时,考虑实现SmartLifecycle 和它的 stop(Runnable) 方法变体。
注意,此停止通知在销毁前不能保证到达: 在常规关闭时,{@code Lifecycle} bean将首先收到一个停止通知,然后才传播常规销毁回调; 在上下文的生命周期内的刷新或中止时,只调用销毁方法
对于容器,这将把停止信号传播到应用的所有组件
*/
void stop();
/**
* 检查此组件是否正在运行。
* 1. 只有该方法返回false时,start方法才会被执行。
* 2. 只有该方法返回true时,stop(Runnable callback)或stop()方法才会被执行。
*/
boolean isRunning();
}
ApplicationContext本身接收启动和停止信号(例如在运行时停止/重启场景)时,spring容器将在容器上下文中找出所有实现了LifeCycle及其子类接口的类,并一一调用它们实现的类。spring是通过委托给生命周期处理器LifecycleProcessor来实现这一点的。
3. 扩展接口
那么,如果Spring容器上下文没有显式的调用start和destory(或者close,stop)等方法时,我们也需要做到生命周期回调,怎么做?
SmartLifecycle可以做到这一点,它继承自Lifecycle接口,新增了如下几个方法:
如果该Lifecycle
类所在的上下文在调用refresh
时,希望能够自己自动进行回调,则返回true
,false的值表明组件打算通过显式的start()调用来启动,类似于普通的Lifecycle实现。
public interface Phased {
int getPhase();
}
public interface SmartLifecycle extends Lifecycle, Phased {
//默认是最大值
int DEFAULT_PHASE = Integer.MAX_VALUE;
/**
* 根据该方法的返回值决定是否执行start方法。<br/>
* 返回true时start方法会被自动执行,返回false则不会。
*/
default boolean isAutoStartup() {
return true;
}
/**
* SmartLifecycle子类的才有的方法,当isRunning方法返回true时,该方法才会被调用。
异步停止bean。
*/
default void stop(Runnable callback) {
//注意点:如果你让isRunning返回true,需要执行stop这个方法,那么就不要忘记调用callback.run()。
//否则在你程序退出时,Spring的DefaultLifecycleProcessor会认为你这个TestSmartLifecycle没有stop完成,程序会一直卡着结束不了,等待一定时间(默认超时时间30秒)后才会自动结束。
// PS:如果你想修改这个默认超时时间,可以按下面思路做,当然下面代码是springmvc配置文件形式的参考,在SpringBoot中自然不是配置xml来完成,这里只是提供一种思路。
// <bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
// <!-- timeout value in milliseconds -->
// <property name="timeoutPerShutdownPhase" value="10000"/>
// </bean>
stop();
callback.run();
}
//最低phase的对象首先启动,最后关闭
//最高phase的对象最后启动,首先关闭
@Override
default int getPhase() {
return DEFAULT_PHASE;
}
}
网友评论