Spring Boot整合ElasticSearch实战 - 第511篇
Transaction rolled back because it has been marked as - 第512篇
一文讲清楚SpringBoot项目打包jar后运行报错template might not exist - 第514篇
idea springboot woff/woff2/eot/ttf/svg等小图标不显示的问题 - 第515篇
Noisee AI中文站网页版 AI 音乐生成视频全新登场,快来抢先体验——国内第一个登场的中文站来袭 - 516篇
悟纤:师傅,你说有没有更优雅的方式,可以在Spring Boot的启动和关闭的时候进行一些资源的操作呐。
师傅:当然是有了,常用的 一些方式是使用@PostConstruct和@PreDestroy,但在有些场景,资源无法精准的被关停,那么这个时候可以使用SmartLifecycle。
悟纤:师傅,看着很厉害的样子呢 ,那师傅赶紧和我分享一下呗。
师傅:拿起小板凳和隔壁的小姐姐一起学习起来~
导读
最近在开发一个AI音乐项目(地址在下面)的时候,在使用队列的时候,想在程序启动和关闭的时候,对队列进行一些操作,一开始的时候@PostConstruct和@PreDestroy,但还是无法很好的进行关停,后面了解到SmartLifecycle,这个确实很好用。
项目体验地址:https://suno4.cn/#/?i=8NCBS8_WXTT
前言
在SpringBoot的应用中,我们通常会利用@PostConstruct和@PreDestroy注解,在Bean初始化或销毁时执行一些操作,这些操作都处于Bean声明周期的层面。
然而,在某些情况下,我们可能会遇到一些遗漏的场景,比如希望在容器本身的生命周期事件(如容器启动、停止)上执行一些操作,一个典型的例子就是在Spring Boot中启动内嵌的Web容器。这时候,该如何处理呢?
这就是我们需要利用Spring提供的另一个接口Lifecycle。接下来,我们将介绍一下Lifecycle接口以及比它更智能的SmartLifecycle。
接口Lifecycle
在SpringBoot应用中如果没有调用AbstractApplicationContext#start方法,只是实现了Lifecycle接口,是不会执行Lifecycle接口中的启动方法和isRunning方法的。但在应用退出时会执行Lifecycle#isRunning方法判断该Lifecycle是否已经启动,如果返回true则调用Lifecycle#stop()停止方法。
如果使用者没有显式的调用容器的start()和stop()方法,Lifecycle的接口方法不会被执行。
而在一般的项目中,我们很少这样显式的去调用,所以就需要一个更“聪明”的类来处理,这就是SmartLifecycle。
接口SmartLifecycle
可以看到SmartLifecy继承了Lifecycle,所以也就拥有了Lifecycle的能力:
start()方法:容器启动后调用
stop()方法:容器停止时调用
isRunning():检查此组件是否正在运行。
(1)只有该方法返回false时,start方法才会被执行。
(2)只有该方法返回true时,stop(Runnable callback)或stop()方法才会被执行。
SmartLifecycle继承自Lifecycle,提供了更丰富的功能:第一,start()方法无需容器显式调用就可以被执行;第二,可以控制多SmartLifecycle实例的执行顺序。
getPhase():如果有多个实现接口SmartLifecycle的类,则这些类的start的执行顺序按getPhase方法返回值从小到大执行。
例如:1比2先执行,-1比0先执行。stop方法的执行顺序则相反,getPhase返回值较大类的stop方法先被调用,小的后被调用。
如何使用呢?很简单
import org.springframework.context.SmartLifecycle;
import org.springframework.stereotype.Component;
public class MySmartLifecycle implements SmartLifecycle {
private volatile boolean running = false;
/**
* 如果该`Lifecycle`类所在的上下文在调用`refresh`时,希望能够自己自动进行回调,则返回`true`,
* false的值表明组件打算通过显式的start()调用来启动,类似于普通的Lifecycle实现。
* 默认就是true,所以可以不用重写此方法。
*/
// @Override
// public boolean isAutoStartup() {
// return true;
// }
/**
* 1. 主要在该方法中启动任务或者其他异步服务,比如开启MQ接收消息<br/>
* 2. 当上下文被刷新(所有对象已被实例化和初始化之后)时,将调用该方法,
* 默认生命周期处理器将检查每个SmartLifecycle对象的isAutoStartup()方法返回的布尔值。
* 如果为“true”,则该方法会被调用,而不是等待显式调用自己的start()方法。
*/
public void start() {
System.out.println("MySmartLifecycle容器启动完成 ...");
running = true;
}
/**
* SmartLifecycle子类的才有的方法,当isRunning方法返回true时,该方法才会被调用。
* 很多框架中的源码中,都会把真正逻辑写在stop()方法内。
* 比如quartz和Redis的spring支持包。
*/
public void stop(Runnable callback) {
System.out.println("MySmartLifecycle容器停止,执行回调函数");
stop();
// 如果你让isRunning返回true,需要执行stop这个方法,那么就不要忘记调用callback.run()。
// 否则在程序退出时,Spring的DefaultLifecycleProcessor会认为这个MySmartLifecycle没有stop完成,程序会一直卡着结束不了,等待一定时间(默认超时时间30秒)后才会自动结束。
callback.run();
}
/**
* 接口Lifecycle子类的方法,只有非SmartLifecycle的子类才会执行该方法。<br/>
* 1. 该方法只对直接实现接口Lifecycle的类才起作用,对实现SmartLifecycle接口的类无效。<br/>
* 2. 方法stop()和方法stop(Runnable callback)的区别只在于,后者是SmartLifecycle子类的专属。
*/
public void stop() {
System.out.println("MySmartLifecycle容器停止 ...");
running = false;
}
/**
* 1. 只有该方法返回false时,start方法才会被执行。<br/>
* 2. 只有该方法返回true时,stop(Runnable callback)或stop()方法才会被执行。
*/
public boolean isRunning() {
System.out.println("MySmartLifecycle检查运行状态 ...");
return running;
}
/**
* 如果有多个实现接口SmartLifecycle的类,则这些类的start的执行顺序按getPhase方法返回值从小到大执行。<br/>
* 例如:1比2先执行,-1比0先执行。stop方法的执行顺序则相反,getPhase返回值较大类的stop方法先被调用,小的后被调用。
*
*/
public int getPhase() {
return 0;
}
}
启动的日志打印:
MySmartLifecycle检查运行状态 ...
MySmartLifecycle容器启动完成 ...
关闭的日志打印:
MySmartLifecycle检查运行状态 ...
MySmartLifecycle容器停止,执行回调函数
MySmartLifecycle容器停止 ...
SmartLifecycle使用场景
(1)异步初始化或销毁操作: SmartLifecycle接口允许在容器启动或关闭过程中执行异步操作。这对于需要在应用程序启动或关闭时执行长时间运行的任务或资源清理操作非常有用。
(2)有序启动和关闭: SmartLifecycle可以指定组件的启动和关闭顺序,确保在启动或关闭过程中其他组件已经准备好或者已经完成。当你的组件在启动的时候,有依赖关系的话,那么就可以SmartLifecycle来进行控制组件的启动顺序。
(3)动态决定启动和关闭: SmartLifecycle接口中的方法能够让组件动态地决定何时启动或关闭。这使得在特定条件满足时才启动或关闭组件成为可能,从而提高了系统的灵活性和可控性。
(4)状态管理: SmartLifecycle接口提供了方法来查询组件的当前状态,例如是否已经启动或停止。这对于在应用程序的其他部分中根据组件状态做出决策或执行特定的逻辑非常有用。
(5)资源监控器的启动和停止: 如果应用程序中存在资源监控器,可以使用SmartLifecycle接口来启动和停止这些监控器。在应用程序启动时,监控器可以开始监控资源的使用情况。在应用程序关闭时,可以停止监控器并释放资源。
以下是一些具体的SmartLifecycle接口的应用场景:
(1)数据库连接池的管理: 在应用程序启动时,可以利用SmartLifecycle接口来初始化数据库连接池。在应用程序关闭时,可以利用SmartLifecycle接口来优雅地关闭数据库连接池,确保所有数据库连接都已释放。
(2)缓存的初始化和销毁: 在应用程序启动时,可以使用SmartLifecycle接口来初始化缓存并加载数据。在应用程序关闭时,可以使用SmartLifecycle接口来优雅地销毁缓存并释放资源。
(3)定时任务的管理: 如果应用程序中存在定时任务,可以使用SmartLifecycle接口来启动和关闭这些定时任务。在应用程序启动时,定时任务可以注册并开始执行。在应用程序关闭时,可以优雅地停止定时任务的执行。