欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?Lifecycle的使用小結(jié)

 更新時(shí)間:2022年05月06日 16:11:31   作者:程序員小杰  
這篇文章主要介紹了Spring?Lifecycle的使用,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

前言

小杰在前面的文章講過可以使用 @PostConstructInitializingBean 、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();
}

image-20220108151717136

多個(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é)論,那就是 CustomizeSmartLifecycle2start方法會(huì)先執(zhí)行,然后 CustomizeSmartLifecycle2stop方法最后執(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方法返回 trueSmartLifecycle。而 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在枚舉類型中增加自定義方法詳解

    Java在枚舉類型中增加自定義方法詳解

    這篇文章主要介紹了Java在枚舉類型中增加自定義方法詳解,對于枚舉類型來說,除了無法繼承它以外,基本可以將它看作一個(gè)普通的類,這意味著你可以在里面增加自定義的方法,甚至可以增加一個(gè) main() 方法,需要的朋友可以參考下
    2023-11-11
  • JVM教程之內(nèi)存管理和垃圾回收(三)

    JVM教程之內(nèi)存管理和垃圾回收(三)

    這篇文章主要介紹了JVM學(xué)習(xí)筆記的第三篇內(nèi)存管理和垃圾回收,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • mybatis中字段名與關(guān)鍵字相同問題

    mybatis中字段名與關(guān)鍵字相同問題

    這篇文章主要介紹了mybatis中字段名與關(guān)鍵字相同問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Java構(gòu)造方法 super 及自定義異常throw合集詳解用法

    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

    這篇文章主要為大家介紹了從零開始Java實(shí)現(xiàn)Parser?Combinator過程及原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Springboot+Mybatis-plus不使用SQL語句進(jìn)行多表添加操作及問題小結(jié)

    Springboot+Mybatis-plus不使用SQL語句進(jìn)行多表添加操作及問題小結(jié)

    這篇文章主要介紹了在Springboot+Mybatis-plus不使用SQL語句進(jìn)行多表添加操作,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • Springboot整合log4j2日志全解總結(jié)

    Springboot整合log4j2日志全解總結(jié)

    這篇文章主要介紹了Springboot整合log4j2日志全解總結(jié),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-12-12
  • mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說明

    mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說明

    這篇文章主要介紹了mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • JavaWeb中Servlet的深入理解

    JavaWeb中Servlet的深入理解

    Java Servlet 是運(yùn)行在 Web 服務(wù)器或應(yīng)用服務(wù)器上的程序,它是作為來自 Web 瀏覽器或其他 HTTP 客戶端的請求和 HTTP 服務(wù)器上的數(shù)據(jù)庫或應(yīng)用程序之間的中間層
    2021-10-10
  • C++內(nèi)存管理看這一篇就夠了

    C++內(nèi)存管理看這一篇就夠了

    這篇文章主要介紹了C/C++中的內(nèi)存管理小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08

最新評論