什么是钩子函数,在学习钩子函数之前,小编先提一个问题。
请问在Spring中,如果JVM异常终止,Spring是如何保证会释放掉占用的资源,比如说数据库连接等资源呢?
钩子函数非常简单,简单到小编只用摘抄一段Spring代码即可。走你,现在开始。
问题
我们知道在Spring中定义销毁方法有两种方式
- 实现
DisposableBean 的destroy 方法。 - 使用
@PreDestroy 注解修饰方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | @Component public class DataCollectBean implements DisposableBean { /** * 第一种方法实现 DisposableBean#destroy方法 * * @throws Exception 异常 */ @Override public void destroy() throws Exception { System.err.println("执行销毁方法"); } /** * 第二种方法使用PreDestroy注解声明销毁方法 */ @PreDestroy public void customerDestroy() { System.err.println("执行自定义销毁方法"); } } |
那么在什么时候执行销毁方法?
- 主动执行销毁bean
1 2 3 4 5 6 | public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args); DataCollectBean bean = run.getBean(DataCollectBean.class); //1. 主动销毁bean run.getBeanFactory().destroyBean(bean); } |
- JVM关闭时候自动执行销毁方法。
这里就要用到钩子函数了,
如果我们是SpringBoot项目我们看到在SpringApplication启动时候会注册一个钩子函数
如何定义钩子函数?
简直太简单了,没有任何学习成本。一行代码就能搞定。
1 2 3 4 5 6 7 8 9 10 11 12 | public class HooksTester { public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { System.out.println("钩子函数执行"); } })); //当主动关闭应用 while (true); } } |
触发钩子函数的场景
只要不是机器断电,强制kill -9 强制杀进程,都会触发。
钩子函数能做什么?
正如上图所示优雅停机,在项目将要关闭时候,主动释放程序占用的资源信息,释放db连接池的连接等其他占用的资源信息。
如果我们是
Spring定义的钩子函数中会去执行,
我们看下源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | protected void doClose() { // Check whether an actual close attempt is necessary... if (this.active.get() && this.closed.compareAndSet(false, true)) { if (logger.isDebugEnabled()) { logger.debug("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(); // Reset local application listeners to pre-refresh state. if (this.earlyApplicationListeners != null) { this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } // Switch to inactive. this.active.set(false); } } |
可以看到:doClose()方法会执行bean的destroy(),也会执行SmartLifeCycle的stop()方法,我们就可以通过重写这些方法来实现对象的关闭,生命周期的管理,实现平滑shutdown
感谢您的阅读,本文由 程序猿升级课 版权所有。如若转载,请注明出处:程序猿升级课(https://blog.springlearn.cn/)