Spring優雅關閉之:ShutDownHook


轉載自:https://blog.csdn.net/qq_26323323/article/details/89814410

 

2020/02/26重新編輯一下

前面介紹ShutDownHook的基本使用方法,但是沒有清楚的表述如何在SpringBoot中運用,這里我們來補充一下:

查閱SpringBoot官方文檔有這么一段描述:

 

1.10. Application Exit

 

Each SpringApplication registers a shutdown hook with the JVM to ensure that the ApplicationContext closes gracefully on exit. All the standard Spring lifecycle callbacks (such as the DisposableBean interface or the @PreDestroy annotation) can be used.

 

官方介紹了兩種方法:

1. 直接實現DisposableBean接口,實現destroy方法即可

@Slf4j
@Component
public class CustomShutdownHook implements DisposableBean {

    @Override
    public void destroy() throws Exception {
    }

}

 

2. 在方法上使用@PreDestroy注解,類似@PostConstruct注解使用方法。

  

1. Runtime.addShutDownHook(Thread hook)

// 創建HookTest,我們通過main方法來模擬應用程序
public class HookTest {
 
    public static void main(String[] args) {
 
        // 添加hook thread,重寫其run方法
        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
            public void run() {
                System.out.println("this is hook demo...");
                // TODO
            }
        });
 
        int i = 0;
        // 這里會報錯,我們驗證寫是否會執行hook thread
        int j = 10/i;
        System.out.println("j" + j);
    }
}

 

2. Runtime.addShutDownHook(Thread hook)應用場景

    * 程序正常退出

    * 使用System.exit()

    * 終端使用Ctrl+C觸發的中斷

    * 系統關閉

    * OutofMemory宕機

    * 使用Kill pid殺死進程(使用kill -9是不會被調用的)

 

3. Spring如何添加鈎子函數

// 通過這種方式來添加鈎子函數
ApplicationContext.registerShutdownHook();
 
// 通過源碼可以看到,
@Override
public void registerShutdownHook() {
    if (this.shutdownHook == null) {
        // No shutdown hook registered yet.
        this.shutdownHook = new Thread() {
            @Override
            public void run() {
                synchronized (startupShutdownMonitor) {
                    doClose();
                }
            }
        };
        // 也是通過這種方式來添加
        Runtime.getRuntime().addShutdownHook(this.shutdownHook);
    }
}
 
// 重點是這個doClose()方法
 
protected void doClose() {
    // Check whether an actual close attempt is necessary...
    if (this.active.get() && this.closed.compareAndSet(false, true)) {
        if (logger.isInfoEnabled()) {
            logger.info("Closing " + this);
        }
 
        LiveBeansView.unregisterApplicationContext(this);
 
        try {
            // Publish shutdown event.
            publishEvent(new ContextClosedEvent(this));
        }
        catch (Throwable ex) {
            logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
        }
 
        // Stop all Lifecycle beans, to avoid delays during individual destruction.
        if (this.lifecycleProcessor != null) {
            try {
                this.lifecycleProcessor.onClose();
            }
            catch (Throwable ex) {
                logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
            }
        }
 
        // Destroy all cached singletons in the context's BeanFactory.
        destroyBeans();
 
        // Close the state of this context itself.
        closeBeanFactory();
 
        // Let subclasses do some final clean-up if they wish...
        onClose();
 
        // Switch to inactive.
        this.active.set(false);
    }
}

可以看到:doClose()方法會執行bean的destroy(),也會執行SmartLifeCycle的stop()方法,我們就可以通過重寫這些方法來實現對象的關閉,生命周期的管理,實現平滑shutdown


免責聲明!

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



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