Springboot优雅停止服务的几种方法程序并没有进行优雅关机。而一些没有执行完的程序会直接退出。很多时候我们需要安全的停止服务,也就是继续处理未完成的工作。比如停止一些依赖的服务,输出一些日志,发送一些信号给其他应用系统。这对于保证系统的高可用性是非常必要的。那么我们就来看看几种停止springboot的方法吧。首先是Springboot提供的actuator函数,可以进行shutdown、health、info等,默认情况下actuator的shutdown是禁用的,我们需要开启它。首先引入actuator的maven依赖。 org.springframework.bootspring-boot-starter-actuator然后打开shutdown节点,将/actuator/shutdown暴露到web访问权限也已设置。除了shutdown,还有health和infowebaccesses。如果你打开management.endpoints.web.exposure.include=*,你可以。将以下配置设置为application.properties。设置服务的端口号为3333server.port=3333management.endpoint.shutdown.enabled=truemanagement.endpoints.web.exposure.include=shutdown接下来我们创建一个springboot项目,然后设置一个bean对象,并配置预销毁方法。这将在停止时打印语句。bean的整个生命周期分为创建、初始化、销毁,销毁操作会在最终关闭时进行。在被销毁的方法中执行输出日志。packagecom.hqs.springboot.shutdowndemo.bean;importjavax.annotation.PreDestroy;/***@authorhuangqingshi*@Date2019-08-17*/publicclassTerminateBean{@PreDestroypublicvoidpreDestroy(){System.out.println("TerminalBeanisdestroyed");}}做一个配置,然后提供一个获取bean的方法,这样bean对象就会被初始化。packagecom.hqs.springboot.shutdowndemo.config;importcom.hqs.springboot.shutdowndemo.bean.TerminateBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;/***@authorhuangqingshi*@Date2019-08-17*/@ConfigurationpublicclassShutDownConfig{@BeanpublicTerminateBeangetTerminateBean(){returnnewTerminateBean();}}在启动类中输出一条启动日志。当项目启动时,你会看到启动输出,然后我们执行停止命令。curl-XPOSThttp://localhost:3333/actuator/shutdown下面的日志可以输出启动时的日志打印和停止时的日志打印,程序同时停止了。是不是很神奇。第二种方法也比较简单。在程序启动时获取上下文,然后在主程序启动时关闭上下文。这样程序在关闭的时候也会调用PreDestroy注解。以下方法在程序启动十秒后关闭程序。/*method2:usectx.closetoshutdownallapplicationcontext*/ConfigurableApplicationContextctx=SpringApplication.run(ShutdowndemoApplication.class,args);try{TimeUnit.SECONDS.sleep(10);}catch(InterruptedExceptione){e.printStackTrace();}ctx.close();第三种方法是在springboot启动时,将进程号写入一个app.pid文件中。可以指定生成的路径,直接通过命令cat/Users/huangqingshi/app.id|停止服务即可xargskill,此时bean对象的PreDestroy方法也会被调用。这种方法比较常用。写一个start.sh启动springboot程序,然后写一个stop程序停止服务。 /*method3:generateapidinaspecifiedpath,whileusecommandtoshutdownpid:'cat/Users/huangqingshi/app.pid|xargskill'*/SpringApplicationapplication=newSpringApplication(ShutdowndemoApplication.class);application.addListeners(newApplicationPidFileWriter("/Users/huangqingshi/app.pid"));应用程序运行();第四种方法,通过调用一个SpringApplication.exit()方法,也可以退出程序,同时会生成一个exitcode,传递给所有的context。这是一个JVM挂钩。通过调用这个方法,所有的PreDestroy方法都会被执行和停止,并将具体的退出代码传递给所有的Context。此错误代码也可以通过调用System.exit(exitCode)传递给JVM。程序执行后,最终会输出:Processfinishedwithexitcode0,给JVM一个SIGNAL。/*method4:exitthisapplicationusingstaticmethod*/ConfigurableApplicationContextctx=SpringApplication.run(ShutdowndemoApplication.class,args);exitApplication(ctx);publicstaticvoidexitApplication(ConfigurableApplicationContextcontext){intexitCode=SpringApplication.exit(context,(ExitCodeGenerator)()->0);exit(exitCode);}第五个方法是自己写一个Controller,然后把写好的Controller拿到程序的上下文中,然后调用自己配置的Controller方法退出程序。调用自己写的/shutDownContext方法关闭程序:curl-XPOSThttp://localhost:3333/shutDownContext。packagecom.hqs.springboot.shutdowndemo.controller;importorg.springframework.beans.BeansException;importorg.springframework.context.ApplicationContext;importorg.springframework.context.ApplicationContextAware;importorg.springframework.context.ConfigurableApplicationContext;importorg.springframework.web.bind。annotation.GetMapping;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RestController;/***@authorhuangqingshi*@Date2019-08-17*/@RestControllerpublicclassShutDownControllerimplementsApplicationContextAware{privateApplicationContextcontext;@PostMapping("/shutDownContext")publicStringshutDownContext(){ConfigurableApplicationContextctx=(ConfigurableApplicationContext)context;ctx.close();return"contextisshutdown";}@GetMapping("/")publicStringgetIndex(){return"OK";}@OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext)抛出BeansException{context=applicationContext;}}好了,springboot的优雅关机方式也实现了。也有同学问如何暴力制止。简单直接kill-9对应的PID总结一下:以上方法实现起来比较简单,但是实际工作中需要考虑的点还是很多的。例如,需要保护暴露的点不被其他人使用。一般必须加一些防火墙,或者只在内网使用,以保证程序安全。在实际工作中,第三种更为常用。一般当程序使用内存队列或线程池时,最好优雅关闭,将未处理的内存队列或未处理的程序保存在线程池中。.但是因为关闭比较快,所以最好不要在服务停止的时候处理大量的数据操作,这样会影响程序停止。