网站开发的书,销售单页网站,wordpress3.9下载,福州直播app开发公司1、关闭流程
停止接收请求和内部线程。判断是否有线程正在执行。等待正在执行的线程执行完毕。停止容器。
2、关闭过程有新的请求 在kill Spring Boot项目时#xff0c;如果有访问请求过来#xff0c;请求会被拒绝并返回错误提示。 在kill Spring Boot项目时#xff0c;Sp…1、关闭流程
停止接收请求和内部线程。判断是否有线程正在执行。等待正在执行的线程执行完毕。停止容器。
2、关闭过程有新的请求 在kill Spring Boot项目时如果有访问请求过来请求会被拒绝并返回错误提示。 在kill Spring Boot项目时Spring Boot应用会先停止接收请求和内部线程然后判断是否有线程正在执行如果有正在执行的线程就等待线程执行完毕最后停止容器。因此当有访问请求过来时请求会被拒绝并返回错误提示。
3、预留缓冲时间 Spring Boot的优雅停机功能可以在收到终止信号后不再接受、处理新请求需要在终止进程之前预留一小段缓冲时间以完成正在处理的请求。不要直接使用kill -9杀死进程。
4、优雅停机方式
4.1 通过Actuator的Endpoint机制关闭服务 使用此方法需要先添加spring-boot-starter-actuator监控服务依赖包
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId
/dependency
默认配置下shutdown端点是关闭的需要在application.properties里配置里面开启
management.endpoint.shutdown.enabledtrue
management.endpoints.web.exposure.includeshutdown
执行关闭接口
curl -X POST http://localhost:8080/actuator/shutdown
4.2 使用ApplicationContext的close方法关闭服务 在应用启用的时候获取ApplicationContext对象然后在相关的位置调用close方法就可以关闭服务。
ConfigurableApplicationContext ctx SpringApplication.run(ShutdowndemoApplication.class, args);
try {TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {e.printStackTrace();
}
ctx.close(); 我们也可以自己写一个Controller获取对应的ApplicationContext对象通过api操作调用close方法关停服务示例代码如下
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;Slf4j
Service
Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {private static ApplicationContext applicationContext null;Overridepublic void setApplicationContext(ApplicationContext applicationContext) {SpringContextHolder.applicationContext applicationContext;}Overridepublic void destroy() {SpringContextHolder.clearHolder();}/*** 关闭服务** methodName: shutdownContext* return: void* author: weixiansheng* date: 2023/10/25**/public static void shutdownContext() {((ConfigurableApplicationContext) applicationContext).close();}}import com.ybw.util.SpringContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** author weixiansheng* version V1.0* className ShutdownController* date 2023/10/25**/
RestController
public class ShutdownController {GetMapping(/shutdown)public void shutdown(){SpringContextHolder.shutdownContext();}
}4.3 监听服务pid通过kill方式关闭服务推荐 通过api方式来关停服务在很多人看来并不安全因为一旦接口泄漏了意味着用户可以随便请求这个接口来关闭服务其影响不言而喻因此很多人建议在服务端通过其他的方式来关闭服务比如通过进程命令方式来关停。 在springboot启动的时候将应用进程 ID 写入一个app.pid文件生成的路径可以指定然后通过脚本命令方式来关闭服务。
SpringBootApplication
public class SprintBootDemoApplication {public static void main(String[] args) {SpringApplication application new SpringApplication(SprintBootDemoApplication.class);application.addListeners(new ApplicationPidFileWriter(D:\\app.pid));application.run();}}通过如下命令方式可以安全的关闭服务。
cat /home/app/project1/app.pid | xargs kill 这种方式也是目前在linux操作系统中使用较为普遍的一种解决方案区别在于实现的方式可能不同有的不用写文件通过其他方式来获取应用进程 ID。 注意 如果使用kill -9 pid的方式关闭服务服务的监听器不会收到任何消息类似于直接强杀应用进程此方法不可取 4.4 使用SpringApplication的exit方法关闭服务 通过调用一个SpringApplication.exit(方法也可以退出程序同时将生成一个退出码这个退出码可以传递给所有的context。这个就是一个JVM的钩子通过调用这个方法的话会把所有PreDestroy的方法执行并停止并且传递给具体的退出码给所有Context。通过调用System.exit(exitCode)可以将这个错误码也传给JVM。程序执行完后最后会输出Process finished with exit code 0给JVM一个SIGNAL。
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.ApplicationPidFileWriter;
import org.springframework.context.ConfigurableApplicationContext;SpringBootApplication
public class SprintBootDemoApplication {public static void main(String[] args) {ConfigurableApplicationContext ctx SpringApplication.run(SprintBootDemoApplication.class, args);exitApplication(ctx);}public static void exitApplication(ConfigurableApplicationContext context) {int exitCode SpringApplication.exit(context, (ExitCodeGenerator) () - 0);System.exit(exitCode);}
}
日志如下
[INFO ] 2023-10-25 15:49:05.640 [main] c.y.s.SprintBootDemoApplication - Starting SprintBootDemoApplication using Java 17.0.8 on LAPTOP-V56V2EJT with PID 44520 (D:\git-code\mygit\learn\spring\sprint-boot-demo\target\classes started by weixiansheng in D:\git-code\mygit\learn\spring\sprint-boot-demo)
[INFO ] 2023-10-25 15:49:05.643 [main] c.y.s.SprintBootDemoApplication - The following 1 profile is active: dev
[INFO ] 2023-10-25 15:49:06.638 [main] o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
[INFO ] 2023-10-25 15:49:06.647 [main] o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler [http-nio-8080]
[INFO ] 2023-10-25 15:49:06.648 [main] o.a.catalina.core.StandardService - Starting service [Tomcat]
[INFO ] 2023-10-25 15:49:06.649 [main] o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.60]
[INFO ] 2023-10-25 15:49:06.738 [main] o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
[INFO ] 2023-10-25 15:49:06.738 [main] o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1024 ms
[INFO ] 2023-10-25 15:49:07.007 [main] o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler [http-nio-8080]
[INFO ] 2023-10-25 15:49:07.031 [main] o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path
[INFO ] 2023-10-25 15:49:07.039 [main] c.y.s.SprintBootDemoApplication - Started SprintBootDemoApplication in 1.969 seconds (JVM running for 3.815)
Disconnected from the target VM, address: 127.0.0.1:53475, transport: socketProcess finished with exit code 04.5 总结 在真实的工作中的时候4.3比较常用程序中一般使用内存队列或线程池的时候最好要优雅的关机将内存队列没有处理的保存起来或线程池中没处理完的程序处理完。但是因为停机的时候比较快所以停服务的时候最好不要处理大量的数据操作这样会影响程序停止。 以上这几种方法实现的话比较简单但是真实工作中还需要考虑的点还很多比如需要保护暴露的点不被别人利用一般要加一些防火墙或者只在内网使用保证程序安全。