Spring?Lifecycle的使用小結(jié)
前言
小杰在前面的文章講過可以使用 @PostConstruct
、InitializingBean
、xml init
、 @PreDestroy
、DisposableBean
、xml destroy
來處理 Bean 的初始化和銷毀,上述這些操作是屬于 Bean 生命周期的。
那如果我想在容器本身的生命周期(比如容器啟動(dòng)、停止)上做一些工作怎么辦呢?Spring 提供了以下接口。
Lifecycle
定義啟動(dòng)/停止生命周期方法的通用接口。
public interface Lifecycle { /** * 容器啟動(dòng)后調(diào)用 */ void start(); /** * 容器停止時(shí)調(diào)用 */ void stop(); /** * 檢查此組件是否正在運(yùn)行。 * 1. 只有該方法返回false時(shí),start方法才會(huì)被執(zhí)行。 * 2. 只有該方法返回true時(shí),stop()方法才會(huì)被執(zhí)行。 */ boolean isRunning(); }
自定義Lifecycle實(shí)現(xiàn)類
@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(); } } 結(jié)果: isRunning ====> false start ====> isRunning ====> true stop ====>
使用 Lifecycle
這種方式,需要顯示的調(diào)用容器的 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
。并且新增了幾個(gè)方法:
- isAutoStartup:是否自動(dòng)啟動(dòng)。為 treu,則自動(dòng)調(diào)用
start()
;為 false,則需要顯示調(diào)用start()
。 - stop:當(dāng) isRunning 方法返回 true 時(shí),該方法才會(huì)被調(diào)用。
- getPhase:來自于
Phased
接口,當(dāng)容器中有多個(gè)實(shí)現(xiàn)了SmartLifecycle
的類,這個(gè)時(shí)候可以依據(jù)getPhase
方法返回值來決定start
方法、stop
方法的執(zhí)行順序。start
方法執(zhí)行順序按照getPhase
方法返回值從小到大執(zhí)行,而stop
方法則相反。比如: 啟動(dòng)時(shí):1 比 3 先執(zhí)行,-1 比 1 先執(zhí)行,退出時(shí):3 比 1 先退出,1 比 -1 先退出。
自定義SmartLifecycle實(shí)現(xiàn)類
@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; } }
將代碼進(jìn)行啟動(dòng),控制臺打印如下內(nèi)容:
public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppApplication.class); //context.start(); //context.stop(); } 結(jié)果: CustomizeSmartLifecycle isRunning() ==== false CustomizeSmartLifecycle start()
發(fā)現(xiàn)并沒有執(zhí)行 stop
方法,這是因?yàn)槿萜鲉栴}。如果在Spring Boot
項(xiàng)目會(huì)自動(dòng)執(zhí)行的,小伙伴可以試一試。
在本例中,還是需要顯示調(diào)用 stop
方法。
public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppApplication.class); //context.start(); context.stop(); } 結(jié)果: CustomizeSmartLifecycle isRunning() ==== false CustomizeSmartLifecycle start() CustomizeSmartLifecycle isRunning() ==== true CustomizeSmartLifecycle stop(Runnable callback)
發(fā)現(xiàn)執(zhí)行了stop(Runnable callback)
,并沒有執(zhí)行 stop
方法。這是因?yàn)楫?dāng)前類是 SmartLifecycle
的子類,如果要執(zhí)行 stop
方法,需要在stop(Runnable callback)
顯示調(diào)用。
@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); }
啟動(dòng)結(jié)果如下:
CustomizeSmartLifecycle isRunning() ==== false
CustomizeSmartLifecycle start()
CustomizeSmartLifecycle isRunning() ==== true
CustomizeSmartLifecycle stop(Runnable callback)
CustomizeSmartLifecycle stop()
注意:在stop(Runnable callback)
方法中不要忘記調(diào)用 callback.run()
方法。否則DefaultLifecycleProcessor
會(huì)認(rèn)為這個(gè)SmartLifecycle
沒有stop
完成,程序會(huì)等待一定時(shí)間,默認(rèn)30秒后才會(huì)自動(dòng)結(jié)束。
@Override public void stop(Runnable callback) { System.out.println("CustomizeSmartLifecycle stop(Runnable callback)"); //stop(); //callback.run(); }
多個(gè)實(shí)現(xiàn)類
@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。按照前面所說的結(jié)論,那就是 CustomizeSmartLifecycle2
的start
方法會(huì)先執(zhí)行,然后 CustomizeSmartLifecycle2
的stop
方法最后執(zhí)行。我們一起來看看執(zhí)行結(jié)果吧!
public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppApplication.class); //context.start(); context.stop(); }
執(zhí)行結(jié)果:
CustomizeSmartLifecycle2 isRunning() =====> false
CustomizeSmartLifecycle2 start() =====>
CustomizeSmartLifecycle isRunning() ==== false
CustomizeSmartLifecycle start()
CustomizeSmartLifecycle isRunning() ==== true
CustomizeSmartLifecycle stop(Runnable callback)
CustomizeSmartLifecycle2 isRunning() =====> true
CustomizeSmartLifecycle2 stop(Runnable callback) =====>
跟結(jié)論保持一致。
源碼分析
基本的使用就到此結(jié)束啦!我們來結(jié)合源碼分析分析吧!
我們來到 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. // 默認(rèn)調(diào)用 DefaultLifecycleProcessor 的 onRefresh 方法 // 找出 Lifecycle Bean 執(zhí)行 start 方法,默認(rèn)情況下是沒有Lifecycle Bean的,需要自己定義 getLifecycleProcessor().onRefresh(); // Publish the final event. // 發(fā)布事件 ContextRefreshedEvent 是一個(gè)事件 publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
getLifecycleProcessor()
方法獲得容器中的 LifecycleProcessor
對象,默認(rèn)就是 DefaultLifecycleProcessor
。
LifecycleProcessor
public interface LifecycleProcessor extends Lifecycle { /** * Notification of context refresh, e.g. for auto-starting components. * 上下文刷新的通知,例如 用于自動(dòng)啟動(dòng)組件 */ void onRefresh(); /** * Notification of context close phase, e.g. for auto-stopping components. * 上下文關(guān)閉的通知,例如 用于自動(dòng)停止組件。 */ void onClose(); }
接口中就定義的兩個(gè)方法。onRefresh
、onClose
。
onRefresh
我們先來看一下 onRefresh
方法的內(nèi)部邏輯,分析它是如何自動(dòng)調(diào)用 start
方法的。
@Override public void onRefresh() { startBeans(true); this.running = true; } private void startBeans(boolean autoStartupOnly) { // 獲取所有的Lifecycle Bean Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans(); // 將Lifecycle Bean 按階段分組,階段通過實(shí)現(xiàn) Phased 接口得到 Map<Integer, LifecycleGroup> phases = new HashMap<>(); // 遍歷所有Lifecycle Bean 按階段值進(jìn)行分組 lifecycleBeans.forEach((beanName, bean) -> { // 當(dāng)autoStartupOnly=false,顯示調(diào)用 start()方法進(jìn)行啟動(dòng),會(huì)觸發(fā)全部的Lifecycle; // 當(dāng)autoStartupOnly=true,調(diào)用容器的 refresh 方法啟動(dòng),只會(huì)觸發(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) { // 調(diào)用 Lifecycle 的 start 方法 phases.get(key).start(); } } }
這里注意一下 autoStartupOnly
的值為 true
。
- autoStartupOnly=true,調(diào)用容器的
refresh
方法,由容器調(diào)用onRefresh
方法自動(dòng)啟動(dòng),只會(huì)觸發(fā)isAutoStartup
方法返回true
的SmartLifecycle
。而isAutoStartup
屬性,小杰在分析SmartLifecycle
的時(shí)候已經(jīng)講過。 - autoStartupOnly=false,顯示調(diào)用
start()
方法進(jìn)行啟動(dòng),會(huì)觸發(fā)全部的Lifecycle
@Override public void start() { getLifecycleProcessor().start(); publishEvent(new ContextStartedEvent(this)); } //傳入 false @Override public void start() { startBeans(false); this.running = true; }
onClose
onClose
在我沒有找到調(diào)用點(diǎn),但是 onClose
內(nèi)部會(huì)調(diào)用stopBeans()
方法。我們直接分析stopBeans
方法。
stopBeans
方法跟 startBeans
的邏輯大體差不多,然后調(diào)用 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); // 按階段值進(jìn)行分組 if (group == null) { // this.timeoutPerShutdownPhase 就是等待時(shí)間 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) { //調(diào)用 stop 方法 phases.get(key).stop(); } } }
stop
創(chuàng)建一個(gè) CountDownLatch
對象,如果 count
不為 0 ,則線程進(jìn)行等待,默認(rèn)等待 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的個(gè)數(shù) 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)) { //調(diào)用 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 { //調(diào)用 await() 方法的線程會(huì)被掛起,等待一定的時(shí)間后,如果 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); // 這里就是為什么要調(diào)用 callback.run() 的原因 // 傳入的是一個(gè) lambad 表達(dá)式,所以需要調(diào)用callback.run(),才會(huì)執(zhí)行 lambad 體 // 在lambad 體才會(huì)執(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); } } } }
關(guān)于Lifecycle
的使用與源碼分析就到這啦!
到此這篇關(guān)于Spring Lifecycle的使用的文章就介紹到這了,更多相關(guān)Spring Lifecycle使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java構(gòu)造方法 super 及自定義異常throw合集詳解用法
異常是程序中的一些錯(cuò)誤,但不是所有錯(cuò)誤都是異常,且錯(cuò)誤有時(shí)候是可以避免的,super可以理解為是指向自己超(父)類對象的一個(gè)指針,而這個(gè)超類指的是離自己最近的一個(gè)父類,構(gòu)造器也叫構(gòu)造方法、構(gòu)造函數(shù),是一種特殊類型的方法,負(fù)責(zé)類中成員變量(域)的初始化2021-10-10從零開始Java實(shí)現(xiàn)Parser?Combinator
這篇文章主要為大家介紹了從零開始Java實(shí)現(xiàn)Parser?Combinator過程及原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05Springboot+Mybatis-plus不使用SQL語句進(jìn)行多表添加操作及問題小結(jié)
這篇文章主要介紹了在Springboot+Mybatis-plus不使用SQL語句進(jìn)行多表添加操作,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說明
這篇文章主要介紹了mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09