在Spring Boot Document中,他们说'每个SpringApplication都会向JVM注册一个关闭钩子,以确保在退出时优雅地关闭ApplicationContext .
当我在shell命令上单击 ctrl+c
时,可以正常关闭应用程序 . 如果我在 生产环境 机器中运行应用程序,我必须使用命令 java -jar ProApplicaton.jar
. 但是我无法关闭shell终端,否则会关闭进程 .
如果我运行像 nohup java -jar ProApplicaton.jar &
这样的命令,我不能使用 ctrl+c
正常关闭它 .
在 生产环境 环境中启动和停止Spring Boot应用程序的正确方法是什么?
12 回答
如果您正在使用 Actuator 模块,则可以通过
JMX
或HTTP
关闭应用程序(如果 endpoints 已启用)(将endpoints.shutdown.enabled=true
添加到application.properties
文件中) ./shutdown
- 允许应用程序正常关闭(默认情况下不启用) .根据 endpoints 的暴露方式,敏感参数可用作安全提示 . 例如,敏感 endpoints 在通过
HTTP
访问时需要用户名/密码(如果未启用Web安全性,则只需禁用) .来自Spring boot documentation
关于@ Jean-Philippe Bond的回答,
这是一个maven快速示例,供maven用户配置HTTP endpoints ,使用spring-boot-starter-actuator关闭 spring 启动Web应用程序,以便您可以复制和粘贴:
1.Maven pom.xml:
2.application.properties:
列出所有 endpoints here:
3.发送一个post方法来关闭app:
安全注意事项:
如果您需要auth保护的关闭方法,您可能还需要
configure details:
这是另一个选项,不需要您更改代码或暴露关闭 endpoints . 创建以下脚本并使用它们来启动和停止您的应用程序 .
start.sh
启动您的应用并将进程ID保存在文件中
stop.sh
使用保存的进程ID停止您的应用
start_silent.sh
如果您需要使用远程计算机或CI管道中的ssh启动应用程序,请使用此脚本来启动应用程序 . 直接使用start.sh可以让shell挂起 .
例如 . 重新部署您的应用程序,您可以使用以下命令重新启动
您可以使springboot应用程序将PID写入文件,您可以使用pid文件停止或重新启动或使用bash脚本获取状态 . 要将PID写入文件,请使用ApplicationPidFileWriter向SpringApplication注册一个侦听器,如下所示:
然后编写一个bash脚本来运行spring boot应用程序 . Reference .
现在您可以使用该脚本来启动,停止或重新启动 .
我没有公开任何 endpoints 并启动( with nohup in background and without out files created through nohup )并使用shell脚本停止(使用 KILL PID gracefully and force kill if app is still running after 3 mins ) . 我只是创建可执行jar并使用PID文件编写器来编写PID文件并将Jar和Pid存储在与应用程序名称相同的文件夹中,并且shell脚本也具有相同的名称,最后是start和stop . 我称这些停止脚本并通过jenkins管道启动脚本 . 到目前为止没有问题 . 完美适用于8个应用程序(非常通用的脚本,易于应用于任何应用程序) .
主类
YML文件
这是启动脚本(start-appname.sh):
这是停止脚本(stop-appname.sh):
Spring Boot提供了几个应用程序监听器,同时尝试创建应用程序上下文,其中一个是ApplicationFailedEvent . 我们可以用来了解应用程序上下文初始化与否的天气 .
将上述侦听器类添加到SpringApplication .
SpringApplication隐式地向JVM注册一个关闭钩子,以确保在退出时正常关闭ApplicationContext . 这也将调用所有使用
@PreDestroy
注释的bean方法 . 这意味着我们不必在启动应用程序中明确使用ConfigurableApplicationContext
的registerShutdownHook()
方法,就像我们在spring核心应用程序中所做的那样 .所有答案似乎都缺少这样一个事实:您可能需要在正常关闭期间以协调的方式完成某些工作(例如,在企业应用程序中) .
@PreDestroy
允许您在单个bean中执行关闭代码 . 更复杂的东西看起来像这样:从Spring Boot 1.5开始,没有开箱即用的优雅关机制 . 一些spring-boot启动器提供此功能:
https://github.com/jihor/hiatus-spring-boot
https://github.com/gesellix/graceful-shutdown-spring-boot
https://github.com/corentin59/spring-boot-graceful-shutdown
我是nr的作者 . 1.首发名为"Hiatus for Spring Boot" . 它适用于负载均衡器级别,即只是将服务标记为OUT_OF_SERVICE,而不会以任何方式干扰应用程序上下文 . 这允许进行正常关闭,并且意味着,如果需要,可以将服务停止服务一段时间,然后恢复生命 . 缺点是它不会停止JVM,你必须使用
kill
命令 . 当我在容器中运行所有东西时,这对我来说没什么大不了的,因为无论如何我将不得不停下来移除容器 .第2和第3款或多或少基于Andy Wilkinson的this post . 它们单向工作 - 一旦触发,它们最终会关闭上下文 .
如果您使用的是maven,则可以使用Maven App assembler plugin .
The daemon mojo(嵌入JSW)将输出带有start / stop参数的shell脚本 .
stop
将正常关闭/杀死您的Spring应用程序 .可以使用相同的脚本将您的maven应用程序用作Linux服务 .
如果你在linux环境中,你所要做的就是从/etc/init.d/里面创建你的.jar文件的符号链接 .
然后,您可以像任何其他服务一样启动应用程序
关闭应用程序
这样,退出终端时应用程序不会终止 . 应用程序将使用stop命令正常关闭 .
它们有很多方法可以关闭spring应用程序 . 一种是在
ApplicationContext
上调用close():您的问题建议您通过执行
Ctrl+C
来关闭应用程序,这通常用于终止命令 . 在这种情况下...使用
endpoints.shutdown.enabled=true
不是最佳配方 . 这意味着您公开一个终点来终止您的应用程序 . 因此,根据您的使用案例和您的环境,您必须确保它...Ctrl+C
应该在你的情况下运作良好 . 我认为你的问题是由&符号引起的(&)更多解释:Spring Application Context可能已经注册了JVM运行时的关闭钩子 . 见ApplicationContext documentation .
我不知道Spring Boot是否自动配置了这个钩子 . 我认为是 .
在
Ctrl+C
上,shell会向前台应用程序发送INT
信号 . 这意味着"please interrupt your execution" . 应用程序可以捕获此信号并在终止之前进行清理(Spring注册的挂钩),或者只是忽略它(坏) .nohup
是执行以下程序的命令,其中陷阱忽略HUP信号 . 挂机时HUP用于终止程序(例如关闭ssh连接) . 此外,它重定向输出以避免程序阻塞消失的TTY .nohup
不会忽略INT信号 . 所以它不会阻止Ctrl+C
工作 .我认为你的问题是由&符号引起的,而不是由nohup引起的 .
Ctrl+C
向前台进程发送信号 . &符导致您的应用程序在后台运行 . 一个解决方案:做使用
kill -9
或kill -KILL
是错误的,因为应用程序(此处为JVM)无法捕获它以正常终止 .另一种解决方案是将您的应用程序带回前台 . 然后
Ctrl+C
将起作用 . 看看Bash Job控件,更准确地说是在fg
上 .