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

posted @ 2019-11-27 18:13  codest  阅读(8171)  评论(0编辑  收藏  举报