在使用 SpringBoot 的时候,都要涉及到服务的停止和启动,当我们停止服务的时候,很多时候大家都是kill -9 直接把程序进程杀掉,这样程序不会执行优雅的关闭。而且一些没有执行完的程序就会直接退出。

我们很多时候都需要安全的将服务停止,也就是把没有处理完的工作继续处理完成。比如停止一些依赖的服务,输出一些日志,发一些信号给其他的应用系统,这个在保证系统的高可用是非常有必要的。那么咱么就来看一下几种停止SpringBoot 的方法。

第一种就是 SpringBoot 提供的actuator的功能,它可以执行shutdown, health, info等,默认情况下,actuator的shutdown是disable的,我们需要打开它。首先引入acturator的maven依赖。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

然后将shutdown节点打开,也将/actuator/shutdown暴露web访问也设置上,除了shutdown之外还有health, info的web访问都打开的话将management.endpoints.web.exposure.include=*就可以。将如下配置设置到application.properties里边。设置一下服务的端口号为3333。

server.port=3333
management.endpoint.shutdown.enabled=true
management.endpoints.web.exposure.include=shutdown

接下来,咱们创建一个SpringBoot工程,然后设置一个bean对象,配置上PreDestroy方法。这样在停止的时候会打印语句。bean的整个生命周期分为创建、初始化、销毁,当最后关闭的时候会执行销毁操作。在销毁的方法中执行一条输出日志。

package com.hqs.springboot.shutdowndemo.bean;import javax.annotation.PreDestroy;publicclassTerminateBean{@PreDestroy
publicvoid preDestroy() {System.out.println("TerminalBean is destroyed");
}} 

做一个configuration,然后提供一个获取bean的方法,这样该bean对象会被初始化。

package com.hqs.springboot.shutdowndemo.config;import com.hqs.springboot.shutdowndemo.bean.TerminateBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
publicclassShutDownConfig{@Bean
publicTerminateBean getTerminateBean() {returnnewTerminateBean();
}} 

在启动类里边输出一个启动日志,当工程启动的时候,会看到启动的输出,接下来咱们执行停止命令。

curl -X POST http://localhost:3333/actuator/shutdown 

以下日志可以输出启动时的日志打印和停止时的日志打印,同时程序已经停止。是不是比较神奇。

第二种方法也比较简单,获取程序启动时候的context,然后关闭主程序启动时的context。这样程序在关闭的时候也会调用PreDestroy注解。如下方法在程序启动十秒后进行关闭。

/* method 2: use ctx.close to shutdown all application context */
ConfigurableApplicationContext ctx = SpringApplication.run(ShutdowndemoApplication.class, args);try{TimeUnit.SECONDS.sleep(10);} catch(InterruptedException e) {e.printStackTrace();
}ctx.close(); 

第三种方法,在SpringBoot启动的时候将进程号写入一个app.pid文件,生成的路径是可以指定的,可以通过命令 cat /Users/huangqingshi/app.id | xargs kill 命令直接停止服务,这个时候bean对象的PreDestroy方法也会调用的。这种方法大家使用的比较普遍。写一个start.sh用于启动springboot程序,然后写一个停止程序将服务停止。  

/* method 3 : generate a pid in a specified path, while use command to shutdown pid :'cat /Users/huangqingshi/app.pid | xargs kill' */
SpringApplication application = newSpringApplication(ShutdowndemoApplication.class);application.addListeners(newApplicationPidFileWriter("/Users/huangqingshi/app.pid"));application.run();

第四种方法,通过调用一个SpringApplication.exit()方法也可以退出程序,同时将生成一个退出码,这个退出码可以传递给所有的context。这个就是一个JVM的钩子,通过调用这个方法的话会把所有PreDestroy的方法执行并停止,并且传递给具体的退出码给所有Context。通过调用System.exit(exitCode)可以将这个错误码也传给JVM。程序执行完后最后会输出:Process finished with exit code 0,给JVM一个SIGNAL。整编:微信公众号,搜云库技术团队,ID:souyunku

/* method 4: exit this application using static method */
ConfigurableApplicationContext ctx = SpringApplication.run(ShutdowndemoApplication.class, args);
exitApplication(ctx);
publicstaticvoid exitApplication(ConfigurableApplicationContext context) {int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);System.exit(exitCode);
}

第五种方法,自己写一个Controller,然后将自己写好的Controller获取到程序的context,然后调用自己配置的Controller方法退出程序。通过调用自己写的/shutDownContext方法关闭程序:curl -X POST http://localhost:3333/shutDownContext。

package com.hqs.springboot.shutdowndemo.controller;import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
publicclassShutDownControllerimplementsApplicationContextAware{privateApplicationContext context;@PostMapping("/shutDownContext")
publicString shutDownContext() {ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) context;ctx.close();
return"context is shutdown";
}@GetMapping("/")
publicString getIndex() {return"OK";
}@Override
publicvoid setApplicationContext(ApplicationContext applicationContext) throwsBeansException{context = applicationContext;
}
}

好了,SpringBoot的优雅关闭方法也都实现好了,也有同学问,如何暴力停止呢,简单,直接kill -9 相应的PID即可

总结一下:

以上这几种方法实现的话比较简单,但是真实工作中还需要考虑的点还很多,比如需要保护暴露的点不被别人利用,一般要加一些防火墙,或者只在内网使用,保证程序安全。整编:微信公众号,搜云库技术团队,ID:souyunku

在真实的工作中的时候第三种比较常用,程序中一般使用内存队列或线程池的时候最好要优雅的关机,将内存队列没有处理的保存起来或线程池中没处理完的程序处理完。但是因为停机的时候比较快,所以停服务的时候最好不要处理大量的数据操作,这样会影响程序停止。

好了,大家觉得还没看全的话,可以访问我的GIT代码:

https://github.com/stonehqs/shutdowndemo.git


原作者:JUST DO IT
原文链接:Springboot 优雅停止服务的几种方法
原出处:博客园
侵删

python 程序停止打印日志_优雅停止 SpringBoot 服务,拒绝 kill -9 暴力停止!相关推荐

  1. python 程序停止打印日志_停止 Spring Boot 服务的几种优雅姿势

    在使用 Spring Boot 的时候,都要涉及到服务的停止和启动,当我们停止服务的时候,很多时候大家都是 kill -9 直接把程序进程杀掉,这样程序不会执行优雅的关闭.而且一些没有执行完的程序就会 ...

  2. 如果优雅停止 SpringBoot 服务,应该拒绝 kill -9 暴力停止

    搞IT 在使用 SpringBoot 的时候,都要涉及到服务的停止和启动,当我们停止服务的时候,很多时候大家都是kill -9 直接把程序进程杀掉,这样程序不会执行优雅的关闭.而且一些没有执行完的程序 ...

  3. Python程序可打印今天的年,月和日

    In the below example – we are implementing a python program to print the current/ today's year, mont ...

  4. python 程序停止打印日志_Python日志打印

    简单示例 import sys import ctypes import logging import logging.handlers reload(sys) sys.setdefaultencod ...

  5. python代码执行过程记录_优雅的记录Python程序日志

    1 本篇概要 logging模块的调用: 保存log日志为文件: 调整输入日志等级: 修改日志消息格式: 2 前言 在使用Python编写程序的过程中,我们经常使用print()函数打印一些信息到控制 ...

  6. python程序运行结果不停_关于python:在进程运行时不断打印Subprocess输出

    要从我的python脚本启动程序,我使用以下方法: def execute(command): process = subprocess.Popen(command, shell=True, stdo ...

  7. 后台运行java程序并打印日志

    在Linux服务器上运行jar包,服务器上输入 java -jar app_name.jar,如果想让程序一直在服务器上运行,则需要用nohup命令.命令如下: nohup java -jar app ...

  8. python程序员年薪百万_想要成为年薪百万的Python程序员,这套面试题别错过

    近几年来,Python的运用范围越来越广,发展势头十分强劲.小到网页建设.网站搭建,大到人工智能AI.云计算.人脸识别.大数据分析等等尖端技术,都基于Python编程语言来实现. 在小伙伴们通过参加培 ...

  9. python程序怎么保存运行_教你如何编写、保存与运行 Python 程序

    第一步 接下来我们将看见如何在 Python 中运行一个传统的"Hello World"程序.Python教程本章将会教你如何编写.保存与运行 Python 程序. 通过 Pyth ...

最新文章

  1. JSP显示页面和数据库乱码
  2. Django模板、配置文件、静态文件及案例实现(创建模板、设置模板查找路径、模板接收视图传入的数据、模板处理数据、BASE_DIR、DEBUG、本地语言与时区、App应用配置)
  3. dos2unix install on mac_mac2019新品唇釉来啦!MAC有色唇油试色
  4. 我眼里的Exchange 2010 之:1—DAG
  5. 24. Leetcode 61. 旋转链表 (链表-基础操作类-旋转链表)
  6. c++17(18)-重载I/O运算符
  7. Apache Spark 1.5新特性介绍
  8. private static final long serialVersionUID = 1L;详解
  9. 8. Python 数据类型
  10. 微信公众号测试功能点
  11. 一个特殊的List去重问题的解决方案
  12. mysql日期函数转换_Mysql日期函数大全 转
  13. C++14::lambda函数的类型
  14. php response.write,ASP_RESPONSE.WRITE和lt;%=%的区别,RESPONSE.WRITE与%=%都是ASP程 - phpStudy...
  15. layui后台管理系统 - 权限树表格
  16. Linux系统环境:DM8数据库安装
  17. 用JavaScript实现简单的乘法计算
  18. react使用@tweenjs/tween.js实现数字动态增长
  19. (一)、写一个怪物的类,类中有属性姓名(name),攻击力(attack),有打人的方法(fight)。(方法的重写)...
  20. Buffon投针实验

热门文章

  1. 其实,这仅仅是个开始
  2. MFC控件随窗口大小变化原理及实现
  3. woocommerce分类页面模板_小程序模板怎么设计才好看?
  4. Jlink接口的Jtag和SWD接口定义
  5. SOL注入——HTTP头部注入(2)(七)
  6. 文件包含(include require)
  7. linux .o文件 复制,Linux I/O实现文件复制
  8. 请验证实例名称是否正确并且 sql server 已配置为允许远程连接_安装MySQL后,需要调整的10个性能配置项...
  9. 关于Android studio3.0的坑之butterknife 7.0.1(低版本)
  10. html 右侧滚动,HTMLCSS实现左侧固定宽度右侧内容可滚动