Spring?Lifecycle的使用小結
前言
小杰在前面的文章講過可以使用 @PostConstruct、InitializingBean 、xml init、 @PreDestroy 、DisposableBean 、xml destroy來處理 Bean 的初始化和銷毀,上述這些操作是屬于 Bean 生命周期的。
那如果我想在容器本身的生命周期(比如容器啟動、停止)上做一些工作怎么辦呢?Spring 提供了以下接口。
Lifecycle
定義啟動/停止生命周期方法的通用接口。
public interface Lifecycle {
/**
* 容器啟動后調用
*/
void start();
/**
* 容器停止時調用
*/
void stop();
/**
* 檢查此組件是否正在運行。
* 1. 只有該方法返回false時,start方法才會被執(zhí)行。
* 2. 只有該方法返回true時,stop()方法才會被執(zhí)行。
*/
boolean isRunning();
}自定義Lifecycle實現類
@Component
public class CustomizeLifecycle implements Lifecycle {
private volatile boolean running = false;
@Override
public void start() {
running = true;
System.out.println("start ==== ");
}
@Override
public void stop() {
running = false;
System.out.println("stop ==== ");
}
@Override
public boolean isRunning() {
return running;
}
}
測試
@ComponentScan(basePackages = {"com.gongj.lifecycle"})
public class AppApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppApplication.class);
context.start();
context.stop();
}
}
結果:
isRunning ====> false
start ====>
isRunning ====> true
stop ====>
使用 Lifecycle這種方式,需要顯示的調用容器的 start、stop方法。 顯得笨重,所以我們使用另外一種方式 :SmartLifecycle。
SmartLifecycle
public interface SmartLifecycle extends Lifecycle, Phased {
int DEFAULT_PHASE = Integer.MAX_VALUE;
default boolean isAutoStartup() {
return true;
}
default void stop(Runnable callback) {
stop();
callback.run();
}
@Override
default int getPhase() {
return DEFAULT_PHASE;
}
}
看到的源碼定義,SmartLifecycle除了繼承Lifecycle之外,還繼承了 Phased。并且新增了幾個方法:
- isAutoStartup:是否自動啟動。為 treu,則自動調用
start();為 false,則需要顯示調用start()。 - stop:當 isRunning 方法返回 true 時,該方法才會被調用。
- getPhase:來自于
Phased接口,當容器中有多個實現了SmartLifecycle的類,這個時候可以依據getPhase方法返回值來決定start方法、stop方法的執(zhí)行順序。start方法執(zhí)行順序按照getPhase方法返回值從小到大執(zhí)行,而stop方法則相反。比如: 啟動時:1 比 3 先執(zhí)行,-1 比 1 先執(zhí)行,退出時:3 比 1 先退出,1 比 -1 先退出。
自定義SmartLifecycle實現類
@Component
public class CustomizeSmartLifecycle implements SmartLifecycle {
private volatile boolean running = false;
@Override
public void start() {
running = true;
System.out.println("CustomizeSmartLifecycle start()");
}
@Override
public void stop() {
System.out.println("CustomizeSmartLifecycle stop()");
running = false;
}
@Override
public boolean isRunning() {
System.out.println("CustomizeSmartLifecycle isRunning() ==== " + running);
return running;
}
@Override
public boolean isAutoStartup() {
return true;
}
@Override
public void stop(Runnable callback) {
System.out.println("CustomizeSmartLifecycle stop(Runnable callback)");
callback.run();
}
@Override
public int getPhase() {
return 1;
}
}
將代碼進行啟動,控制臺打印如下內容:
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppApplication.class);
//context.start();
//context.stop();
}
結果:
CustomizeSmartLifecycle isRunning() ==== false
CustomizeSmartLifecycle start()
發(fā)現并沒有執(zhí)行 stop方法,這是因為容器問題。如果在Spring Boot項目會自動執(zhí)行的,小伙伴可以試一試。
在本例中,還是需要顯示調用 stop方法。
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppApplication.class);
//context.start();
context.stop();
}
結果:
CustomizeSmartLifecycle isRunning() ==== false
CustomizeSmartLifecycle start()
CustomizeSmartLifecycle isRunning() ==== true
CustomizeSmartLifecycle stop(Runnable callback)發(fā)現執(zhí)行了stop(Runnable callback),并沒有執(zhí)行 stop方法。這是因為當前類是 SmartLifecycle的子類,如果要執(zhí)行 stop方法,需要在stop(Runnable callback)顯示調用。
@Override
public void stop(Runnable callback) {
System.out.println("CustomizeSmartLifecycle stop(Runnable callback)");
stop();
callback.run();
}
或者
@Override
public void stop(Runnable callback) {
SmartLifecycle.super.stop(callback);
}
啟動結果如下:
CustomizeSmartLifecycle isRunning() ==== false
CustomizeSmartLifecycle start()
CustomizeSmartLifecycle isRunning() ==== true
CustomizeSmartLifecycle stop(Runnable callback)
CustomizeSmartLifecycle stop()
注意:在stop(Runnable callback)方法中不要忘記調用 callback.run()方法。否則DefaultLifecycleProcessor會認為這個SmartLifecycle沒有stop完成,程序會等待一定時間,默認30秒后才會自動結束。
@Override
public void stop(Runnable callback) {
System.out.println("CustomizeSmartLifecycle stop(Runnable callback)");
//stop();
//callback.run();
}多個實現類
@Component
public class CustomizeSmartLifecycle2 implements SmartLifecycle {
private volatile boolean running = false;
@Override
public void start() {
running = true;
System.out.println("CustomizeSmartLifecycle2 start() =====>");
}
@Override
public void stop() {
System.out.println("CustomizeSmartLifecycle1 stop() =====>");
running = false;
}
@Override
public boolean isRunning() {
System.out.println("CustomizeSmartLifecycle2 isRunning() =====> " + running);
return running;
}
@Override
public boolean isAutoStartup() {
return true;
}
@Override
public void stop(Runnable callback) {
System.out.println("CustomizeSmartLifecycle2 stop(Runnable callback) =====>");
callback.run();
}
@Override
public int getPhase() {
return -1;
}
}
getPhase方法返回 -1。按照前面所說的結論,那就是 CustomizeSmartLifecycle2的start方法會先執(zhí)行,然后 CustomizeSmartLifecycle2的stop方法最后執(zhí)行。我們一起來看看執(zhí)行結果吧!
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppApplication.class);
//context.start();
context.stop();
}執(zhí)行結果:
CustomizeSmartLifecycle2 isRunning() =====> false
CustomizeSmartLifecycle2 start() =====>
CustomizeSmartLifecycle isRunning() ==== false
CustomizeSmartLifecycle start()
CustomizeSmartLifecycle isRunning() ==== true
CustomizeSmartLifecycle stop(Runnable callback)
CustomizeSmartLifecycle2 isRunning() =====> true
CustomizeSmartLifecycle2 stop(Runnable callback) =====>
跟結論保持一致。
源碼分析
基本的使用就到此結束啦!我們來結合源碼分析分析吧!
我們來到 finishRefresh方法的 getLifecycleProcessor().onRefresh();方法。
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// Initialize lifecycle processor for this context.
//為此上下文初始化生命周期處理器
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
// 默認調用 DefaultLifecycleProcessor 的 onRefresh 方法
// 找出 Lifecycle Bean 執(zhí)行 start 方法,默認情況下是沒有Lifecycle Bean的,需要自己定義
getLifecycleProcessor().onRefresh();
// Publish the final event.
// 發(fā)布事件 ContextRefreshedEvent 是一個事件
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
getLifecycleProcessor()方法獲得容器中的 LifecycleProcessor對象,默認就是 DefaultLifecycleProcessor。
LifecycleProcessor
public interface LifecycleProcessor extends Lifecycle {
/**
* Notification of context refresh, e.g. for auto-starting components.
* 上下文刷新的通知,例如 用于自動啟動組件
*/
void onRefresh();
/**
* Notification of context close phase, e.g. for auto-stopping components.
* 上下文關閉的通知,例如 用于自動停止組件。
*/
void onClose();
}
接口中就定義的兩個方法。onRefresh、onClose。
onRefresh
我們先來看一下 onRefresh方法的內部邏輯,分析它是如何自動調用 start方法的。
@Override
public void onRefresh() {
startBeans(true);
this.running = true;
}
private void startBeans(boolean autoStartupOnly) {
// 獲取所有的Lifecycle Bean
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
// 將Lifecycle Bean 按階段分組,階段通過實現 Phased 接口得到
Map<Integer, LifecycleGroup> phases = new HashMap<>();
// 遍歷所有Lifecycle Bean 按階段值進行分組
lifecycleBeans.forEach((beanName, bean) -> {
// 當autoStartupOnly=false,顯示調用 start()方法進行啟動,會觸發(fā)全部的Lifecycle;
// 當autoStartupOnly=true,調用容器的 refresh 方法啟動,只會觸發(fā)isAutoStartup方法返回true的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) {
// 調用 Lifecycle 的 start 方法
phases.get(key).start();
}
}
}
這里注意一下 autoStartupOnly的值為 true。
- autoStartupOnly=true,調用容器的
refresh方法,由容器調用onRefresh方法自動啟動,只會觸發(fā)isAutoStartup方法返回true的SmartLifecycle。而isAutoStartup屬性,小杰在分析SmartLifecycle的時候已經講過。 - autoStartupOnly=false,顯示調用
start()方法進行啟動,會觸發(fā)全部的Lifecycle
@Override
public void start() {
getLifecycleProcessor().start();
publishEvent(new ContextStartedEvent(this));
}
//傳入 false
@Override
public void start() {
startBeans(false);
this.running = true;
}onClose
onClose在我沒有找到調用點,但是 onClose內部會調用stopBeans()方法。我們直接分析stopBeans方法。
stopBeans方法跟 startBeans的邏輯大體差不多,然后調用 stop方法。
@Override
public void onClose() {
stopBeans();
this.running = false;
}
private void stopBeans() {
// 獲取所有的Lifecycle Bean
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
// 獲得 phase 的值
int shutdownPhase = getPhase(bean);
LifecycleGroup group = phases.get(shutdownPhase);
// 按階段值進行分組
if (group == null) {
// this.timeoutPerShutdownPhase 就是等待時間
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) {
//調用 stop 方法
phases.get(key).stop();
}
}
}
stop
創(chuàng)建一個 CountDownLatch對象,如果 count不為 0 ,則線程進行等待,默認等待 30 s。
public void stop() {
if(this.members.isEmpty()) {
return;
}
if(logger.isDebugEnabled()) {
logger.debug("Stopping beans in phase " + this.phase);
}
this.members.sort(Collections.reverseOrder());
// 創(chuàng)建 CountDownLatch 對象 ,count 為 smartMemberCount
// smartMemberCount 為 SmartLifecycle Bean的個數
CountDownLatch latch = new CountDownLatch(this.smartMemberCount);
Set < String > countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet < > ());
Set < String > lifecycleBeanNames = new HashSet < > (this.lifecycleBeans.keySet());
for(LifecycleGroupMember member: this.members) {
if(lifecycleBeanNames.contains(member.name)) {
//調用 dostop 方法
doStop(this.lifecycleBeans, member.name, latch, countDownBeanNames);
} else if(member.bean instanceof SmartLifecycle) {
// Already removed: must have been a dependent bean from another phase
//將count值減1
latch.countDown();
}
}
try {
//調用 await() 方法的線程會被掛起,等待一定的時間后,如果 count值還沒有為 0 才繼續(xù)執(zhí)行
latch.await(this.timeout, TimeUnit.MILLISECONDS);
if(latch.getCount() > 0 && !countDownBeanNames.isEmpty() && logger.isInfoEnabled()) {
logger.info("Failed to shut down " + countDownBeanNames.size() + " bean" + (countDownBeanNames.size() > 1 ? "s" : "") + " with phase value " + this.phase + " within timeout of " + this.timeout + ": " + countDownBeanNames);
}
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
doStop
doStop 方法的邏輯很簡單。區(qū)分是否是SmartLifecycle類型,如果是執(zhí)行stop(Runnable callback)方法,反之執(zhí)行 stop()方法。
private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName,
final CountDownLatch latch, final Set<String> countDownBeanNames) {
Lifecycle bean = lifecycleBeans.remove(beanName);
if (bean != null) {
String[] dependentBeans = getBeanFactory().getDependentBeans(beanName);
for (String dependentBean : dependentBeans) {
doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames);
}
try {
// 判斷 isRunning 的值
if (bean.isRunning()) {
// 如果是 SmartLifecycle 類型,則執(zhí)行 stop(Runnable callback) 方法
if (bean instanceof SmartLifecycle) {
if (logger.isTraceEnabled()) {
logger.trace("Asking bean '" + beanName + "' of type [" +
bean.getClass().getName() + "] to stop");
}
countDownBeanNames.add(beanName);
// 這里就是為什么要調用 callback.run() 的原因
// 傳入的是一個 lambad 表達式,所以需要調用callback.run(),才會執(zhí)行 lambad 體
// 在lambad 體才會執(zhí)行 latch.countDown()
((SmartLifecycle) bean).stop(() -> {
//將count值減1
latch.countDown();
countDownBeanNames.remove(beanName);
if (logger.isDebugEnabled()) {
logger.debug("Bean '" + beanName + "' completed its stop procedure");
}
});
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Stopping bean '" + beanName + "' of type [" +
bean.getClass().getName() + "]");
}
// 否則執(zhí)行 stop() 方法
bean.stop();
if (logger.isDebugEnabled()) {
logger.debug("Successfully stopped bean '" + beanName + "'");
}
}
}
else if (bean instanceof SmartLifecycle) {
// Don't wait for beans that aren't running...
latch.countDown();
}
}
catch (Throwable ex) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to stop bean '" + beanName + "'", ex);
}
}
}
}
關于Lifecycle的使用與源碼分析就到這啦!
到此這篇關于Spring Lifecycle的使用的文章就介紹到這了,更多相關Spring Lifecycle使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java構造方法 super 及自定義異常throw合集詳解用法
異常是程序中的一些錯誤,但不是所有錯誤都是異常,且錯誤有時候是可以避免的,super可以理解為是指向自己超(父)類對象的一個指針,而這個超類指的是離自己最近的一個父類,構造器也叫構造方法、構造函數,是一種特殊類型的方法,負責類中成員變量(域)的初始化2021-10-10
Springboot+Mybatis-plus不使用SQL語句進行多表添加操作及問題小結
這篇文章主要介紹了在Springboot+Mybatis-plus不使用SQL語句進行多表添加操作,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04
mybatis 集合嵌套查詢和集合嵌套結果的區(qū)別說明
這篇文章主要介紹了mybatis 集合嵌套查詢和集合嵌套結果的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09

