你知道几种关闭SpringBoot应用程序的方法?

2020-04-16  本文已影响0人  java梦想口服液

SpringBoot应用程序的关闭目前总结起来有4种方式:

  1. Rest接口:使用spring-boot-starter-actuator模块里的ShutdownEndpoint
  2. SpringApplication的exit静态方法:直接调用该静态方法即可
  3. JMX:使用SpringBoot内部提供的MXBean
  4. 使用第三方进程管理工具

# Rest接口

Rest接口使用Endpoint暴露出来,需要引入spring-boot-starter-actuator这个stater。

这个关闭应用程序对应的Endpoint是ShutdownEndpoint,直接调用ShutdownEndpoint提供的rest接口即可。得先开启ShutdownEndpoint(默认不开启),以及不进行安全监测:

endpoints.shutdown.enabled: true
endpoints.shutdown.sensitive: false

然后调用rest接口:

curl -X POST http://localhost:8080/shutdown  

可以使用spring-security进行安全监测:

endpoints.shutdown.sensitive: true
security.user.name: admin
security.user.password: admin
management.security.role: SUPERUSER  

然后使用用户名和密码进行调用:

curl -u admin:admin -X POST http://127.0.0.1:8080/shutdown  

这个ShutdownEndpoint底层其实就是调用了Spring容器的close方法:

@Override
public Map<String, Object> invoke() {

  if (this.context == null) {
    return Collections.<String, Object>singletonMap("message",
        "No context to shutdown.");
  }

  try {
    return Collections.<String, Object>singletonMap("message",
        "Shutting down, bye...");
  }
  finally {

    new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          Thread.sleep(500L);
        }
        catch (InterruptedException ex) {
          // Swallow exception and continue
        }
        ShutdownEndpoint.this.context.close();
      }
    }).start();

  }
}

# SpringApplication的exit静态方法

SpringApplication提供了一个exit静态方法,用于关闭Spring容器,该方法还有一个参数exitCodeGenerators表示ExitCodeGenerator接口的数组。

ExitCodeGenerator接口是一个生成退出码exitCode的生成器。

public static int exit(ApplicationContext context,
    ExitCodeGenerator... exitCodeGenerators) {
  Assert.notNull(context, "Context must not be null");
  int exitCode = 0; // 默认的退出码是0
  try {
    try {
      // 构造ExitCodeGenerator集合
      ExitCodeGenerators generators = new ExitCodeGenerators();
      // 获得Spring容器中所有的ExitCodeGenerator类型的bean
      Collection<ExitCodeGenerator> beans = context
          .getBeansOfType(ExitCodeGenerator.class).values();
      // 集合加上参数中的ExitCodeGenerator数组
      generators.addAll(exitCodeGenerators);
      // 集合加上Spring容器中的ExitCodeGenerator集合
      generators.addAll(beans);
      // 遍历每个ExitCodeGenerator,得到最终的退出码exitCode
      // 这里每个ExitCodeGenerator生成的退出码如果比0大,那么取最大的
      // 如果比0小,那么取最小的
      exitCode = generators.getExitCode();
      if (exitCode != 0) { // 如果退出码exitCode不为0,发布ExitCodeEvent事件
        context.publishEvent(new ExitCodeEvent(context, exitCode));
      }
    }
    finally {
      // 关闭Spring容器
      close(context);
    }

  }
  catch (Exception ex) {
    ex.printStackTrace();
    exitCode = (exitCode == 0 ? 1 : exitCode);
  }
  return exitCode;
}

我们写个Controller直接调用exit方法:

@Autowired
private ApplicationContext applicationContext;

@PostMapping("/stop")
public String stop() {
    // 加上自己的权限验证
    SpringApplication.exit(applicationContext);
    return "ok";
}

# JMX

spring-boot-starter-actuator这个stater内部会构造ShutdownEndpointMBean。

使用jconsole可以看到这个MBean:

SpringBoot内部也提供了一个SpringApplicationAdminMXBean,但是需要开启:

spring.application.admin.enabled: true 

# 使用第三方进程管理工具

比如我们的应用程序部署在linux系统上,可以借助一些第三方的进程管理工具管理应用程序的运行,比如supervisor。

设置program:

[program:stop-application]
command=java -jar /yourjar.jar
process_name=%(program_name)s
startsecs=10
autostart=false
autorestart=false
stdout_logfile=/tmp/stop.log
stderr_logfile=/tmp/stop-error.log

使用supervisorctl进入控制台操作应用程序:

supervisor> status
stop-application                 STOPPED   Jun 27 03:50 PM
supervisor> start stop-application
stop-application: started
supervisor> status
stop-application                 RUNNING   pid 27918, uptime 0:00:11
supervisor> stop stop-application
stop-application: stopped
supervisor> status
stop-application                 STOPPED   Jun 27 03:50 PM  

来源:http://fangjian0423.github.io/2017/06/28/springboot-application-exit

上一篇下一篇

猜你喜欢

热点阅读