Lifecycle和SmartLifecycle的正確使用姿勢

一、前言

  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有更豐富的功能。其中有兩點最重要的改進:

  1. 無需容器顯示調用start()方法,就可以回調SmartLifecycle接口的start()
  2. 容器中如果有多個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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章