Lifecycle和SmartLifecycle的正确使用姿势
一、前言 Lifecycle是Spring中最基础的生命周期接口,该接口定义了容器启动和停止的方法。方便开发者扩展自己的特定逻辑,比如启动和停止某些后台进程。 SmartLifecycle是对Lifecycle的一个扩展接口,当我们实现SmartLifecycle接口时,发现需要实现很多方法。很多同学不理解这些方法是干嘛的,今天我们来一起探讨下~二、先说Lifecycle Lifecycle
一、前言
Lifecycle是Spring中最基础的生命周期接口,该接口定义了容器启动和停止的方法。方便开发者扩展自己的特定逻辑,比如启动和停止某些后台进程。
SmartLifecycle是对Lifecycle的一个扩展接口,当我们实现SmartLifecycle接口时,发现需要实现很多方法。很多同学不理解这些方法是干嘛的,今天我们来一起探讨下~
二、先说Lifecycle
Lifecycle常用来管理一个组件的启动和停止,这个组件可以是一个线程、或者是一件事情。有同学可能会有这样的疑惑:开始和停止的逻辑写在一个bean的初始化方法和销毁方法中不可以了吗,为什么要实现个Lifecycle接口呢?这里说明一下,bean的初始化方法和销毁方法是Bean生命周期级别的;而Lifecycle是容器生命周期级别的。
我们来看下使用步骤~
1. 定义一个类并实现Lifecycle接口
public class MyLifecycle implements Lifecycle {
/**
* A 组件的运行状态
*/
private volatile boolean running = false;
/**
* 容器启动后调用
*/
@Override
public void start() {
System.out.println("lifecycle 容器启动完成,启动A组件...");
running = true;
}
/**
* 容器停止时调用
*/
@Override
public void stop() {
System.out.println("lifecycle 收到关闭容器的信号,关闭A组件...");
running = false;
}
/**
* 检查此组件是否正在运行。
* 1. 只有该方法返回false时,start方法才会被执行。
* 2. 只有该方法返回true时,stop(Runnable callback)或stop()方法才会被执行。
*/
@Override
public boolean isRunning() {
System.out.println("lifecycle 检查A组件的运行状态:" + running);
return running;
}
}
Spring每次调用start()和stop()方法之前,都会调用下isRunning()方法。来检测下这个A组件,是否已经启动或停止过了。如果通过isRunning()方法,检测到A组件已经是运行状态了,就无需再调用start()方法启动A组件。
2. 把MyLifecycle交给Spring管理
<bean id="myLifecycle" class="com.kaka.spring.pojo.custom.MyLifecycle"/>
以上配置在lifecycle.xml文件中
3. 执行
@Test
public void lifecycleTest() {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"lifecycle.xml");
// 必须显示调用
classPathXmlApplicationContext.start();
classPathXmlApplicationContext.stop();
}
运行结果
这里强调一下,一定要显示调用容器的start()和stop()方法,Lifecycle的接口方法才会被执行。但是一般项目中(比如ssm和springboot),都不会显示调用容器的start()方法,所以就有了SmartLifecycle接口的出现。
三、再谈SmartLifecycle
SmartLifecycle是Lifecycle的一个子接口,比Lifecycle有更丰富的功能。其中有两点最重要的改进:
- 无需容器显示调用start()方法,就可以回调SmartLifecycle接口的start()
- 容器中如果有多个SmartLifecycle实例,可以方便控制调用顺序。
用法和Lifecycle一样,我们来看下
1. 定义一个类实现SmartLifecycle接口
public class MySmartLifecycle implements SmartLifecycle {
private volatile boolean running = false;
/**
* 如果该`Lifecycle`类所在的上下文在调用`refresh`时,希望能够自己自动进行回调,则返回`true`* ,
* false的值表明组件打算通过显式的start()调用来启动,类似于普通的Lifecycle实现。
*/
@Override
public boolean isAutoStartup() {
return true;
}
/**
* 很多框架中的源码中,都会把真正逻辑写在stop()方法内。
* 比如quartz和Redis的spring支持包
*
* @param callback
*/
@Override
public void stop(Runnable callback) {
System.out.println("smartLifecycle stop runnable 容器停止...");
stop();
callback.run();
}
@Override
public void start() {
System.out.println("smartLifecycle 容器启动完成 ...");
running = true;
}
@Override
public void stop() {
System.out.println("smartLifecycle stop 容器停止 ...");
running = false;
}
@Override
public boolean isRunning() {
System.out.println("smartLifecycle 检查运行状态 ...");
return running;
}
/**
* 阶段值 越小越靠前执行start()方法,越靠后执行stop()方法
*
* @return
*/
@Override
public int getPhase() {
return 0;
}
}
一共需要实现6个方法,确实要不少啊,不是start()和stop()就行了吗?好吧,我们一个个解释下~
方法名 | 描述 |
---|---|
isAutoStartup() | 这个一定要返回true,不然就跟Lifecycle一样了。 |
getPhase() | 控制多个SmartLifecycle的回调顺序的,返回值越小越靠前执行start()方法,越靠后执行stop()方法 |
isRunning() | 与Lifecycle接口中的功能一样,用来判你的断组件是否在运行。 |
start() | 与Lifecycle接口中的功能一样,当刷新容器(也就是启动完成)时调用。 |
stop(Runnable callback) | 当容器停止时,回调该方法。当执行完你自定义的逻辑后,一定要调用下callback.run(); 这个是为了,告诉容器你已停止自己的组件完成。 这里多说一点,很多源码会在该方法内仅写两行代码,参考上面例子。一行是stop();把真正的逻辑转发到stop()这个方法。另一行就是必须调用的callback.run(); |
stop() | 不会被Spring框架调用到! |
2. 把MySmartLifecycle交给Spring管理
<bean id="mySmartLifecycle" class="com.kaka.spring.pojo.custom.MySmartLifecycle"/>
以上配置在lifecycle.xml文件中
3. 执行
@Test
public void lifecycleTest() {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"lifecycle.xml");
// 模拟框架中的停止方法
classPathXmlApplicationContext.stop();
}
执行结果
四、总结
- 需要根据Spring容器的生命周期,来做一些自己的逻辑时,一般都会选择自定义一个类,实现SmartLifecycle这个接口。很少有人会使用Lifecycle
- 容器中有多个SmartLifecycle时,可以使用接口中的getPhase()方法控制回调的顺序。方法返回值越小,越靠前执行start()方法,越靠后执行stop()方法
- SmartLifecycle这个接口的isAutoStartup()方法,一定要返回true,容器启动时才会回调SmartLifecycle的start()方法。
- stop(Runnable callback)方法是有超时时间的,默认为30s。可以通过以下方式设置超时时间
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
<!-- timeout value in milliseconds -->
<property name="timeoutPerShutdownPhase" value="10000"/>
</bean>
更多推荐
所有评论(0)