springboot優雅的關閉應用


  1. 使用actuator,通過發送http請求關閉
  2. 將應用注冊為linux服務,通過service xxx stop關閉

具體這兩種方式如何實現,這里就不說了,網上百度一堆,主要講一下在這兩種情況下web應用listener的一些問題

一般來講,我們的應用都應該在結束的時候對資源進行回收處理,jvm幫我們做了一部分,springboot也做了相應bean的回收,那如果是我們自己創建的線程池或是其他未托管於spring的資源呢?

  1. 在非web的應用中,我們一般使用勾子來實現,從而保證在jvm退出時,能夠進行一些資源的回收(直接kill無法保證執行),kill命令相當於直接把應用干掉,是一種非正常情況下中止應用的方式。ctrl+c,System.exit(),程序正常退出都會觸發勾子

    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
    	            @Override
    	            public void run() {
    	                try {
    	                    shutdown(componentName);
    	                } catch (Exception e) {
    	                    LOGGER.error("shutdown error:", e);
    	                }
    
                }
            }, componentName + <span class="hljs-string">"_shutdown_hook_thread"</span>));</pre> </li> 
    
  2. 在web應用中,勾子就不一定能夠生效了,而是通過實現ServletContextListener接口,可以在context初始化和結束的時候做一些資源創建和回收的操作

    public class ContextListener implements ServletContextListener {
    	    private static final Logger LOGGER = LoggerFactory.getLogger(ContextListener.class);
    
        <span class="hljs-annotation">@Override</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">contextInitialized</span><span class="hljs-params">(ServletContextEvent servletContextEvent)</span> </span>{
            LOGGER.info(<span class="hljs-string">"contextInitialized"</span>);
        }
    
        <span class="hljs-annotation">@Override</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">contextDestroyed</span><span class="hljs-params">(ServletContextEvent servletContextEvent)</span> </span>{
            LOGGER.info(<span class="hljs-string">"contextDestroyed begin..."</span>);
            ShutdownUtil.destroy();
            LOGGER.info(<span class="hljs-string">"contextDestroyed end..."</span>);
        }
    }</pre> </li> 
    

問題來了,在使用第二種方式將springboot應用注冊為linux服務時,發現通過service xxx stop命令停止應用時,contextDestroyed的日志根本沒打印出來,懷疑是LOGGER對象已經被jvm回收,於是改成System.out,這次begin打印出來了,但是並沒有調用 ShutdownUtil.destroy()方法,懷疑同上,具體的機制沒去詳細了解,猜測是springboot自己的回收策略,或者是該插件的坑。

使用actuator的方式沒有問題,會正常的執行destroyed的回收


免責聲明!

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



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