自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

常見(jiàn)Java應(yīng)用如何優(yōu)雅關(guān)閉

開(kāi)發(fā) 前端
在我們進(jìn)行系統(tǒng)升級(jí)的時(shí)候,往往需要關(guān)閉我們的應(yīng)用,然后重啟。在關(guān)閉應(yīng)用前,我們希望做一些前置操作,比如關(guān)閉數(shù)據(jù)庫(kù)、redis連接,清理zookeeper的臨時(shí)節(jié)點(diǎn),釋放分布式鎖,持久化緩存數(shù)據(jù)等等。

一、前言

在我們進(jìn)行系統(tǒng)升級(jí)的時(shí)候,往往需要關(guān)閉我們的應(yīng)用,然后重啟。在關(guān)閉應(yīng)用前,我們希望做一些前置操作,比如關(guān)閉數(shù)據(jù)庫(kù)、redis連接,清理zookeeper的臨時(shí)節(jié)點(diǎn),釋放分布式鎖,持久化緩存數(shù)據(jù)等等。

二、Linux的信號(hào)機(jī)制

在linux上,我們關(guān)閉進(jìn)程主要是使用 kill 的方式。

當(dāng)執(zhí)行該命令以后,linux會(huì)向進(jìn)程發(fā)送一個(gè)信號(hào),進(jìn)程收到以后之后,可以做一些清理工作。

kill 命令默認(rèn)的信號(hào)值為 15 ,即 SIGTERM 信號(hào)。

通過(guò) kill -l 查看linux支持哪些信號(hào):

常見(jiàn)Java應(yīng)用如何優(yōu)雅關(guān)閉

linux提供了 signal() api,可以將信號(hào)處理函數(shù)注冊(cè)上去:

 

  1. #include <signal.h> 
  2. #include <stdio.h> 
  3. #include <unistd.h> 
  4. #include <stdlib.h> 
  5. #include <stdbool.h> 
  6.  
  7. static void gracefulClose(int sig)   
  8.     printf("執(zhí)行清理工作\n"); 
  9.     printf("JVM 已關(guān)閉\n"); 
  10.     exit(0);    //正常關(guān)閉 
  11.  
  12. int main(int argc,char *argv[])   
  13.     if(signal(SIGTERM,gracefulClose) == SIG_ERR) 
  14.         exit(-1); 
  15.  
  16.     printf("JVM 已啟動(dòng)\n"); 
  17.  
  18.     while(true
  19.     { 
  20.         // 執(zhí)行工作 
  21.         sleep(1); 
  22.     } 

三、Java提供的Shutdown Hook

Java并不支持類(lèi)似于linux的信號(hào)機(jī)制,但是提供了 Runtime.addShutdownHook(Thread hook) 的api。

在JVM關(guān)閉前,會(huì)并發(fā)執(zhí)行各個(gè)Hook線程。

 

  1. public class ShutdownHook { 
  2.  
  3.     public static void main(String[] args) throws InterruptedException { 
  4.         Runtime.getRuntime().addShutdownHook(new DbShutdownWork()); 
  5.         System.out.println("JVM 已啟動(dòng)"); 
  6.  
  7.         while(true){ 
  8.             Thread.sleep(10L); 
  9.         } 
  10.     } 
  11.  
  12.     static class DbShutdownWork extends Thread{ 
  13.         public void run(){ 
  14.             System.out.println("關(guān)閉數(shù)據(jù)庫(kù)連接"); 
  15.         } 
  16.     } 

四、Spring Boot提供的優(yōu)雅關(guān)閉功能

我們一般采用如下的方式,啟動(dòng)一個(gè)Spring boot應(yīng)用:

 

  1. public static void main(String[] args) throws Exception {   
  2.     SpringApplication.run(SampleController.class, args); 

SpringApplication.run()代碼如下,會(huì)調(diào)用到refreshContext(context)方法:

 

  1. public ConfigurableApplicationContext run(String... args) {   
  2.     StopWatch stopWatch = new StopWatch(); 
  3.     stopWatch.start(); 
  4.     ConfigurableApplicationContext context = null
  5.     FailureAnalyzers analyzers = null
  6.     configureHeadlessProperty(); 
  7.     SpringApplicationRunListeners listeners = getRunListeners(args); 
  8.     listeners.started(); 
  9.     try { 
  10.         ApplicationArguments applicationArguments = new DefaultApplicationArguments( 
  11.                 args); 
  12.         ConfigurableEnvironment environment = prepareEnvironment(listeners, 
  13.                 applicationArguments); 
  14.         Banner printedBanner = printBanner(environment); 
  15.         context = createApplicationContext(); 
  16.         analyzers = new FailureAnalyzers(context); 
  17.         prepareContext(context, environment, listeners, applicationArguments, 
  18.                 printedBanner); 
  19.         refreshContext(context); 
  20.         afterRefresh(context, applicationArguments); 
  21.         listeners.finished(context, null); 
  22.         stopWatch.stop(); 
  23.         if (this.logStartupInfo) { 
  24.             new StartupInfoLogger(this.mainApplicationClass) 
  25.                     .logStarted(getApplicationLog(), stopWatch); 
  26.         } 
  27.         return context; 
  28.     } 
  29.     catch (Throwable ex) { 
  30.         handleRunFailure(context, listeners, analyzers, ex); 
  31.         throw new IllegalStateException(ex); 
  32.     } 

refreshContext()方法比較簡(jiǎn)單:

 

  1. private void refreshContext(ConfigurableApplicationContext context) {   
  2.     refresh(context);   //調(diào)用ApplicationContext.refresh() 
  3.     if (this.registerShutdownHook) {        //registerShutdownHook默認(rèn)值為true 
  4.         try { 
  5.             context.registerShutdownHook(); 
  6.         } 
  7.         catch (AccessControlException ex) { 
  8.             // Not allowed in some environments. 
  9.         } 
  10.     } 

AbstractApplicationContext.registerShutdownHook()代碼:

 

  1. public void registerShutdownHook() {   
  2.     if (this.shutdownHook == null) { 
  3.         this.shutdownHook = new Thread() { 
  4.             @Override 
  5.             public void run() { 
  6.                 synchronized (startupShutdownMonitor) { 
  7.                     doClose(); 
  8.                 } 
  9.             } 
  10.         }; 
  11.         Runtime.getRuntime().addShutdownHook(this.shutdownHook); 
  12.     } 

很明顯,Spring boot通過(guò)在啟動(dòng)時(shí),向JVM注冊(cè)一個(gè)ShutdownHook,從而實(shí)現(xiàn)JVM關(guān)閉前,正常關(guān)閉Spring容器。而Spring在銷(xiāo)毀時(shí),會(huì)依次調(diào)用bean的destroy動(dòng)作來(lái)銷(xiāo)毀。

五、Dubbo的優(yōu)雅關(guān)閉策略

Dubbo同樣是基于ShutdownHook實(shí)現(xiàn)的。

AbstractConfig的static代碼:

 

  1. static {   
  2.     Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { 
  3.         public void run() { 
  4.             if (logger.isInfoEnabled()) { 
  5.                 logger.info("Run shutdown hook now."); 
  6.             } 
  7.             ProtocolConfig.destroyAll(); 
  8.         } 
  9.     }, "DubboShutdownHook")); 

六、總結(jié)

只要我們的應(yīng)用運(yùn)行在linux平臺(tái)上,所有的優(yōu)雅關(guān)閉方案都是基于linux提供的信號(hào)機(jī)制提供的,JVM也是如此。

Java并沒(méi)有為我們提供與之一一對(duì)應(yīng)的api,而是給出了個(gè)ShutdownHook機(jī)制,也能達(dá)到類(lèi)似的效果,缺點(diǎn)是我們無(wú)法得知JVM關(guān)閉的原因。

像dubbo、spring boot等成熟的開(kāi)源框架,都實(shí)現(xiàn)了自動(dòng)注冊(cè)ShutdownHook的功能,從而避免使用者忘記調(diào)用優(yōu)雅關(guān)閉api引發(fā)問(wèn)題,降低框架的使用難度。

責(zé)任編輯:未麗燕 來(lái)源: 點(diǎn)我達(dá)技術(shù)
相關(guān)推薦

2021-01-19 10:35:49

JVM場(chǎng)景函數(shù)

2022-04-11 08:17:07

JVMJava進(jìn)程

2024-11-13 16:37:00

Java線程池

2021-03-28 09:17:18

JVM場(chǎng)景鉤子函數(shù)

2021-04-20 08:00:31

Redisson關(guān)閉訂單支付系統(tǒng)

2025-01-13 06:00:00

Go語(yǔ)言gRPC

2021-12-06 09:57:25

容器Linux信號(hào)

2021-01-18 13:17:04

鴻蒙HarmonyOSAPP

2025-02-12 00:21:44

Java并發(fā)編程

2021-01-28 14:53:19

PHP編碼開(kāi)發(fā)

2022-06-02 10:02:47

Kubectl更新應(yīng)用Linux

2023-12-20 10:04:45

線程池Java

2022-09-08 07:32:56

JDK7程序管理

2023-10-10 13:23:18

空指針異常Java

2019-11-18 15:50:11

AjaxJavascript前端

2021-07-15 09:47:20

Docker容器命令

2022-01-10 09:35:50

日志語(yǔ)言解析器

2025-01-20 07:10:00

LambdaJavanull

2022-03-07 07:33:24

Spring自定義機(jī)制線程池

2020-12-08 08:08:51

Java接口數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)