常见Java应用如何优雅关闭

一、应用雅关前言

在我们进行系统升级的何优时候,往往需要关闭我们的应用雅关应用,然后重启。何优在关闭应用前,应用雅关我们希望做一些前置操作,何优比如关闭数据库、应用雅关redis连接,何优清理zookeeper的应用雅关临时节点,释放分布式锁,何优持久化缓存数据等等。应用雅关

二、何优Linux的应用雅关信号机制

在linux上,我们关闭进程主要是何优使用 kill 的方式。

当执行该命令以后,应用雅关linux会向进程发送一个信号,进程收到以后之后,可以做一些清理工作。

kill 命令默认的信号值为 15 ,即 SIGTERM 信号。

通过 kill -l 查看linux支持哪些信号:

linux提供了 signal() api,亿华云可以将信号处理函数注册上去:

#include <signal.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <stdbool.h> static void gracefulClose(int sig)   {      printf("执行清理工作\n");     printf("JVM 已关闭\n");     exit(0);    //正常关闭 } int main(int argc,char *argv[])   {      if(signal(SIGTERM,gracefulClose) == SIG_ERR)         exit(-1);     printf("JVM 已启动\n");     while(true)     {          // 执行工作         sleep(1);     } } 

三、Java提供的Shutdown Hook

Java并不支持类似于linux的信号机制,但是提供了 Runtime.addShutdownHook(Thread hook) 的api。

在JVM关闭前,会并发执行各个Hook线程。

public class ShutdownHook {      public static void main(String[] args) throws InterruptedException {          Runtime.getRuntime().addShutdownHook(new DbShutdownWork());         System.out.println("JVM 已启动");         while(true){              Thread.sleep(10L);         }     }     static class DbShutdownWork extends Thread{          public void run(){              System.out.println("关闭数据库连接");         }     } } 

四、Spring Boot提供的优雅关闭功能

我们一般采用如下的方式,启动一个Spring boot应用:

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

SpringApplication.run()代码如下,会调用到refreshContext(context)方法:

public ConfigurableApplicationContext run(String... args) {        StopWatch stopWatch = new StopWatch();     stopWatch.start();     ConfigurableApplicationContext context = null;     FailureAnalyzers analyzers = null;     configureHeadlessProperty();     SpringApplicationRunListeners listeners = getRunListeners(args);     listeners.started();     try {          ApplicationArguments applicationArguments = new DefaultApplicationArguments(                 args);         ConfigurableEnvironment environment = prepareEnvironment(listeners,                 applicationArguments);         Banner printedBanner = printBanner(environment);         context = createApplicationContext();         analyzers = new FailureAnalyzers(context);         prepareContext(context, environment, listeners, applicationArguments,                 printedBanner);         refreshContext(context);         afterRefresh(context, applicationArguments);         listeners.finished(context, null);         stopWatch.stop();         if (this.logStartupInfo) {              new StartupInfoLogger(this.mainApplicationClass)                     .logStarted(getApplicationLog(), stopWatch);         }         return context;     }     catch (Throwable ex) {          handleRunFailure(context, listeners, analyzers, ex);         throw new IllegalStateException(ex);     } } 

refreshContext()方法比较简单:

private void refreshContext(ConfigurableApplicationContext context) {        refresh(context);   //调用ApplicationContext.refresh()     if (this.registerShutdownHook) {         //registerShutdownHook默认值为true         try {              context.registerShutdownHook();         }         catch (AccessControlException ex) {              // Not allowed in some environments.         }     } } 

AbstractApplicationContext.registerShutdownHook()代码:

public void registerShutdownHook() {        if (this.shutdownHook == null) {          this.shutdownHook = new Thread() {              @Override             public void run() {                  synchronized (startupShutdownMonitor) {                      doClose();                 }             }         };         Runtime.getRuntime().addShutdownHook(this.shutdownHook);     } } 

很明显,Spring boot通过在启动时,向JVM注册一个ShutdownHook,从而实现JVM关闭前,正常关闭Spring容器。而Spring在销毁时,会依次调用bean的destroy动作来销毁。

五、Dubbo的优雅关闭策略

Dubbo同样是基于ShutdownHook实现的。云南idc服务商

AbstractConfig的static代码:

static {        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {          public void run() {              if (logger.isInfoEnabled()) {                  logger.info("Run shutdown hook now.");             }             ProtocolConfig.destroyAll();         }     }, "DubboShutdownHook")); } 

六、总结

只要我们的应用运行在linux平台上,所有的优雅关闭方案都是基于linux提供的信号机制提供的,JVM也是如此。

Java并没有为我们提供与之一一对应的api,而是给出了个ShutdownHook机制,也能达到类似的效果,缺点是我们无法得知JVM关闭的原因。

像dubbo、spring boot等成熟的开源框架,都实现了自动注册ShutdownHook的功能,从而避免使用者忘记调用优雅关闭api引发问题,降低框架的使用难度。服务器租用

数据库
上一篇:用户邮箱的静态密码可能已被钓鱼和同一密码泄露。在没有收到安全警报的情况下,用户在适当的时间内不能更改密码。在此期间,攻击者可以随意输入帐户。启用辅助身份验证后,如果攻击者无法获取移动电话动态密码,他将无法进行身份验证。这样,除非用户的电子邮件密码和手机同时被盗,否则攻击者很难破解用户的邮箱。
下一篇:旧域名的外链是否会对新建站点产生影响?