玩轉Spring生命周期之Lifecycle


Lifecycle callbacks

Initialization callbacksDestruction callbacks
要與容器的bean生命周期管理交互,即容器在啟動后和容器在銷毀前對每個bean執行操作,有如下三種方法:

1.實現Spring框架的InitializingBeanDisposableBean接口。容器為前者調用afterPropertiesSet()方法,為后者調用destroy()方法,以允許bean在初始化和銷毀bean時執行某些操作。

public class HelloLifeCycle implements InitializingBean, DisposableBean {
    
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet 啟動");
    }

    public void destroy() throws Exception {
        System.out.println("DisposableBean 停止");
    }
}

2.bean自定義初始化方法和銷毀方法,然后在定義bean時指定初始化方法和銷毀方法

 <bean id="helloLifeCycle" class="com.hzways.life.cycle.HelloLifeCycle" init-method="init3"
          destroy-method="destroy3"/>

3.JSR-250 @PostConstruct和@PreDestroy注解通常被認為是在現代Spring應用程序中接PostConstruct注解用於方法上,該方法在初始化的依賴注入操作之后被執行。這個方法必須在class被放到service之后被執行,這個注解所在的類必須支持依賴注入。

public class HelloLifeCycle {

    @PostConstruct
    private void init2() {
        System.out.println("PostConstruct 啟動");
    }

    @PreDestroy
    private void destroy2() {
        System.out.println("PreDestroy 停止");
    }

}

Note:注意
PostConstruct注解用於方法上,該方法在初始化的依賴注入操作之后被執行。因此,容器必須要開啟支持注解形式的依賴注入的功能,加入如下配置即可:

 <context:annotation-config/>

如果一個bean同時實現上述三種形式,調用順序為:

  • 創建bean時
1. @PostConstruct 注解方式 2. InitializingBean 實現接口方式 3. custom init() 自定義初始化方法方式
  • 銷毀bean時
1. @PreDestroy 注解方式 2. DisposableBean 實現接口方式 3. custom destroy() 自定義銷毀方法方式

Spring bean的生命周期

Startup and shutdown callbacks
結合生命周期機制,生命周期接口定義了任何具有自身生命周期需求的對象的基本方法(例如,啟動和停止一些后台過程):

Lifecycle 生命周期回調鈎子

public interface Lifecycle {
    /**
     * 啟動當前組件
     * <p>如果組件已經在運行,不應該拋出異常
     * <p>在容器的情況下,這會將開始信號 傳播到應用的所有組件中去。
     */
    void start();
    /**
     * (1)通常以同步方式停止該組件,當該方法執行完成后,該組件會被完全停止。當需要異步停止行為時,考慮實現SmartLifecycle 和它的 stop(Runnable) 方法變體。

  注意,此停止通知在銷毀前不能保證到達:
    在常規關閉時,{
@code Lifecycle} bean將首先收到一個停止通知,然后才傳播常規銷毀回調;
    在上下文的生命周期內的刷新或中止時,只調用銷毀方法     對於容器,這將把停止信號傳播到應用的所有組件
*/ void stop(); /** * 檢查此組件是否正在運行。 * 1. 只有該方法返回false時,start方法才會被執行。 * 2. 只有該方法返回true時,stop(Runnable callback)或stop()方法才會被執行。 */ boolean isRunning(); }

LifeCycle定義Spring容器對象的生命周期,任何spring管理對象都可以實現該接口。
然后,當ApplicationContext本身接收啟動停止信號(例如在運行時停止/重啟場景)時,spring容器將在容器上下文中找出所有實現了LifeCycle及其子類接口的類,並一一調用它們實現的類。spring是通過委托給生命周期處理器LifecycleProcessor來實現這一點的。

LifecycleProcessor 生命周期處理器

請注意,LifecycleProcessor本身就是LifeCycle接口的擴展。它還添加了另外兩個方法來響應spring容器上下文的刷新(onRefresh)和關閉(close)。

public interface LifecycleProcessor extends Lifecycle {
    /**
     * 響應Spring容器上下文 refresh
     */
    void onRefresh();

    /**
     * 響應Spring容器上下文 close
     */
    void onClose();
}

Lifecycle 生命周期的不足

常規的LifeCycle接口只是在容器上下文顯式的調用start()/stop()方法時,才會去回調LifeCycle的實現類的start stop方法邏輯。並不意味着在上下文刷新時自動啟動。

我們可以定義一個類實現Lifecycle

public class HelloLifeCycle implements Lifecycle {
    private volatile boolean running = false;

    public HelloLifeCycle() {
        System.out.println("構造方法!!!");
    }

   
    @Override
    public void start() {
        System.out.println("lifycycle start");
        running = true;

    }
   @Override
    public void stop() {
        System.out.println("lifycycle stop");
        running = false;
    }

    @Override
    public boolean isRunning() {
        return running;
    }
}

寫一個測試類並在main方法里面啟動spring容器,這里沒有顯示的調用context的start()close()方法

public static void main(String[] args) throws InterruptedException {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:services.xml");
}

結果是,控制台沒有任何輸出,容器並沒有調用生命周期的回調方法.

當我們將啟動容器的類,顯式的加上start和stop方法后:

public static void main(String[] args) throws InterruptedException {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:services.xml");
        applicationContext.start();
        applicationContext.close();
}

這時我們看控制台,spring容器回調了生命周期的方法

SmartLifecycle 自動的生命周期擴展

那么,如果Spring容器上下文沒有顯式的調用startdestory(或者close,stop)等方法時,我們也需要做到生命周期回調,怎么做?

於是SmartLifecycle可以做到這一點,它繼承自Lifecycle接口,新增了如下幾個方法:

public interface SmartLifecycle extends Lifecycle, Phased {

    /**
      * 如果該`Lifecycle`類所在的上下文在調用`refresh`時,希望能夠自己自動進行回調,則返回`true`* ,
      * false的值表明組件打算通過顯式的start()調用來啟動,類似於普通的Lifecycle實現。
     */
    boolean isAutoStartup();

   
    void stop(Runnable callback);

}

容器中實現了Lifecycle的多個類如果希望有順序的進行回調時,那么啟動和關閉調用的順序可能很重要。如果任何兩個對象之間存在依賴關系,那么依賴方將在依賴后開始,在依賴前停止。然而,有時直接依賴關系是未知的。您可能只知道某個類型的對象應該在另一個類型的對象之前開始。在這些情況下,SmartLifecycle接口定義了另一個選項,即在其超接口上定義的getPhase()方法。

當開始時,getPhase()返回值最小的對象先開始,當停止時,遵循相反的順序。因此,實現SmartLifecycle的對象及其getPhase()方法返回Integer.MIN_VALUE將在第一個開始和最后一個停止。相反,MAX_VALUE將指示對象應該在最后啟動並首先停止(可能是因為它依賴於要運行的其他進程)。

SmartLifecycle對象的默認phase是0。因此,任何實現類的phase的值為負數時都表明一個對象應該在這些標准的生命周期回調之前進行執行,反之亦然。

如您所見,SmartLifecycle定義的stop方法接受一個回調。在實現的關閉過程完成之后,任何實現都必須調用回調的run()方法。這允許在必要時進行異步關閉,因為LifecycleProcessor接口,即DefaultLifecycleProcessor,的默認實現,將等待每個階段中的對象組的超時值來調用這個回調。默認的每個階段超時為30秒。您可以通過在上下文中定義一個名為lifecycleProcessorbean來覆蓋默認的生命周期處理器實例。如果您只想修改超時,那么定義以下內容就足夠了:

<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
    <!-- timeout value in milliseconds -->
    <property name="timeoutPerShutdownPhase" value="10000"/>
</bean>

如前所述,LifecycleProcessor接口也定義了用於刷新關閉上下文的回調方法。后者將簡單地驅動關機過程,就好像已經顯式地調用了stop()一樣,但它將在上下文關閉時發生。另一方面,refresh回調支持SmartLifecycle bean的另一個特性。當刷新上下文(在所有對象實例化和初始化之后)時,將調用這個回調,此時,默認的生命周期處理器將檢查每個SmartLifecycle對象的isAutoStartup()方法返回的布爾值。如果是true,那么該對象將在此時啟動,而不是等待上下文或其自己的start()方法的顯式調用(與上下文刷新不同,上下文啟動不會自動發生在標准上下文實現中)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM