SpringBoot应用程序的关闭

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(默认不开启),以及不进行安全监测:

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

然后调用rest接口:

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

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

1
2
3
4
endpoints.shutdown.sensitive: true
security.user.name: admin
security.user.password: admin
management.security.role: SUPERUSER

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

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

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

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
@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的生成器。

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
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方法:

1
2
3
4
5
6
7
8
9
@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,但是需要开启:

1
spring.application.admin.enabled: true

使用第三方进程管理工具

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

设置program:

1
2
3
4
5
6
7
8
[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进入控制台操作应用程序:

1
2
3
4
5
6
7
8
9
10
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
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
本文作者:Format
原文链接: http://fangjian0423.github.io/2017/06/28/springboot-application-exit/
版权归作者所有,转载请注明出处