精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

別再用kill -9關閉程序了......

系統 Linux
我相信很多人都用過 kill -9 pid 這個命令,徹底殺死進程的意思,一般情況我們使用它沒有上面問題,但是在我們項目中使用它就有可能存在致命的問題。

kill 可將指定的信息送至程序。預設的信息為 SIGTERM(15),可將指定程序終止。若仍無法終止該程序,可使用 SIGKILL(9) 信息嘗試強制刪除程序。程序或工作的編號可利用 ps 指令或 jobs 指令查看。

[[401381]]

圖片來自 Pexels

kill -9 pid ???

講的這個復雜,簡單點來說就是用來殺死 Linux 中的進程,啥?你問我啥是進程?請自行百度。

我相信很多人都用過 kill -9 pid 這個命令,徹底殺死進程的意思,一般情況我們使用它沒有上面問題,但是在我們項目中使用它就有可能存在致命的問題。

kill -9 pid 帶來的問題

由于kill -9 屬于暴力刪除,所以會給程序帶來比較嚴重的后果,那究竟會帶來什么后果呢?

舉個栗子:轉賬功能,再給兩個賬戶進行加錢扣錢的時候突然斷電了?這個時候會發生什么事情?

對于 InnoDB 存儲引擎來說,沒有什么損失,因為它支持事務,但是對于 MyISAM 引擎來說那簡直就是災難,為什么?

假如給 A 賬戶扣了錢,現在需要將 B 賬戶加錢,這個時候停電了,就會造成,A 的錢被扣了,但是 B 沒有拿到這筆錢,這在生產環境是絕對不允許的,kill -9 相當于突然斷電的效果。

當然了,像轉賬這種,肯定不是使用 MyISAM 引擎,但是如今分布式火了起來,跨服務轉賬已經是很平常的事情。

這種時候如果使用 kill -9 去停止服務,那就不是你的事務能保證數據的準確性了,這個時候你可能會想到分布式事務。

這個世界上沒有絕對的安全系統或者架構,分布式事務也是一樣,他也會存在問題,概率很小。

如果一旦發生,損失有可能是無法彌補的,所以一定不能使用 kill -9 去停止服務,因為你不知道他會造成什么后果。

在 MyISAM 引擎中表現的更明顯,比如用戶的信息由兩張表維護,管理員修改用戶信息的時候需要修改兩張表。

但由于你的 kill -9 暴力結束項目,導致只修改成功了一張表,這也會導致數據的不一致性。

這是小事,因為大不了再修改一次,但是金錢、合同這些重要的信息如果由于你的暴力刪除導致錯亂,我覺得可能比刪庫跑路還嚴重,至少刪庫還能恢復,你這個都不知道錯在哪里。

那我們應該怎么結束項目呢?其實 Java 給我們提供了結束項目的功能,比如:Tomcat 可以使用 shutdown.bat/shutdown.sh 進行優雅結束。

什么叫優雅結束?

  • 第一步:停止接收請求和內部線程。
  • 第二步:判斷是否有線程正在執行。
  • 第三步:等待正在執行的線程執行完畢。
  • 第四步:停止容器。

以上四步才是正常的結束流程,那 SpringBoot 怎么正常結束服務呢?下面我介紹幾種正常結束服務的方案,請拿好小本本做好筆記。

優雅結束服務

①kill -15 pid

這種方式也會比較優雅的結束進程(項目),使用他的時候需要慎重,為什么呢?

我們來看個例子,我寫了一個普通的 controller 方法做測試:

  1. @GetMapping(value = "/test"
  2.     public String test(){ 
  3.         log.info("test --- start"); 
  4.         try { 
  5.             Thread.sleep(100000); 
  6.         } catch (InterruptedException e) { 
  7.             e.printStackTrace(); 
  8.         } 
  9.         log.info("test --- end"); 
  10.         return "test"
  11.     } 

代碼很簡單,打印:test — start 之后讓讓程序休眠 100 秒,然后再打印:test — end。

在線程休眠中我們使用 kill -15 pid 來結束這個進程,你們猜 test — end 會被打印嗎?

application.yml:

  1. server: 
  2.   port: 9988 

啟動項目:

  1. sudo mvn spring-boot:run 

這是 maven 啟動 SpringBoot 項目的方式:

看到這個就代表項目啟動成了,找到項目的進程 id:

  1. sudo ps -ef |grep shutdown 

 

這個就是項目的進程號,接下來我們先測試 test 接口,讓線程進入休眠狀態,然后再使用 kill -15 14086 停止項目:

  1. sudo curl 127.0.0.1:9988/test 

回到項目日志:

我們發現請求已經到達服務,并且線程已經成功進入休眠,現在我們 kill -15 14086 結束進程:

  1. sudo kill -15 14086 

回到日志:

  1. 2020-04-24 10:53:14.939  INFO 14086 --- [nio-9988-exec-1] com.ymy.controller.TestController        : test --- start 
  2. 2020-04-24 10:54:02.450  INFO 14086 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor' 
  3. java.lang.InterruptedException: sleep interrupted 
  4.  at java.lang.Thread.sleep(Native Method) 
  5.  at com.ymy.controller.TestController.test(TestController.java:26) 
  6.  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
  7.  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
  8.  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
  9.  at java.lang.reflect.Method.invoke(Method.java:498) 
  10.  at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) 
  11.  at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) 
  12.  at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) 
  13.  at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) 
  14.  at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) 
  15.  at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) 
  16.  at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) 
  17.  at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) 
  18.  at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) 
  19.  at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) 
  20.  at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) 
  21.  at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) 
  22.  at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) 
  23.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) 
  24.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 
  25.  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) 
  26.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 
  27.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 
  28.  at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) 
  29.  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 
  30.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 
  31.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 
  32.  at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) 
  33.  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 
  34.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 
  35.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 
  36.  at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109) 
  37.  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 
  38.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 
  39.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 
  40.  at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) 
  41.  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 
  42.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 
  43.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 
  44.  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) 
  45.  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) 
  46.  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) 
  47.  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) 
  48.  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) 
  49.  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) 
  50.  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) 
  51.  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) 
  52.  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) 
  53.  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) 
  54.  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1594) 
  55.  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) 
  56.  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) 
  57.  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 
  58.  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 
  59.  at java.lang.Thread.run(Thread.java:748) 
  60. 2020-04-24 10:54:04.574  INFO 14086 --- [nio-9988-exec-1] com.ymy.controller.TestController        : test --- end 
  61. 2020-04-24 10:54:04.610 ERROR 14086 --- [nio-9988-exec-1] o.s.web.servlet.HandlerExecutionChain    : HandlerInterceptor.afterCompletion threw exception 
  62.  
  63. java.lang.NullPointerException: null 
  64.  at org.springframework.boot.actuate.metrics.web.servlet.LongTaskTimingHandlerInterceptor.stopLongTaskTimers(LongTaskTimingHandlerInterceptor.java:123) ~[spring-boot-actuator-2.2.6.RELEASE.jar:2.2.6.RELEASE] 
  65.  at org.springframework.boot.actuate.metrics.web.servlet.LongTaskTimingHandlerInterceptor.afterCompletion(LongTaskTimingHandlerInterceptor.java:79) ~[spring-boot-actuator-2.2.6.RELEASE.jar:2.2.6.RELEASE] 
  66.  at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:179) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  67.  at org.springframework.web.servlet.DispatcherServlet.triggerAfterCompletion(DispatcherServlet.java:1427) [spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  68.  at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060) [spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  69.  at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) [spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  70.  at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  71.  at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) [spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  72.  at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  73.  at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) [spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  74.  at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  75.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  76.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  77.  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) [tomcat-embed-websocket-9.0.33.jar:9.0.33] 
  78.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  79.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  80.  at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) [spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  81.  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  82.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  83.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  84.  at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) [spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  85.  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  86.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  87.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  88.  at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109) [spring-boot-actuator-2.2.6.RELEASE.jar:2.2.6.RELEASE] 
  89.  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  90.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  91.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  92.  at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) [spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  93.  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE] 
  94.  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  95.  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  96.  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  97.  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  98.  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  99.  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  100.  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  101.  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  102.  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  103.  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  104.  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  105.  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  106.  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1594) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  107.  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  108.  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_242] 
  109.  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_242] 
  110.  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.33.jar:9.0.33] 
  111.  at java.lang.Thread.run(Thread.java:748) [na:1.8.0_242] 

居然報錯了,但是 test — end 是打印出來了,為什么會報錯呢?

[[401383]]

這就和 sleep 這個方法有關了,在線程休眠期間,當調用線程的 interrupt 方法的時候會導致 sleep 拋出異常。

這里很明顯就是 kill -15 這個命令會讓程序馬上調用線程的 interrupt 方法,目的是為了讓線程停止。

雖然讓線程停止,但線程什么時候停止還是線程自己說的算,這就是為什么我們還能看到:test — end 的原因。

②ConfigurableApplicationContext colse

我們先看怎么實現:

  1. package com.ymy.controller; 
  2.  
  3. import lombok.extern.slf4j.Slf4j; 
  4. import org.springframework.beans.BeansException; 
  5. import org.springframework.context.ApplicationContext; 
  6. import org.springframework.context.ApplicationContextAware; 
  7. import org.springframework.context.ConfigurableApplicationContext; 
  8. import org.springframework.web.bind.annotation.GetMapping; 
  9. import org.springframework.web.bind.annotation.PostMapping; 
  10. import org.springframework.web.bind.annotation.RestController; 
  11.  
  12. @RestController 
  13. @Slf4j 
  14. public class TestController  implements ApplicationContextAware { 
  15.  
  16.     private  ApplicationContext  context; 
  17.  
  18.     @Override 
  19.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
  20.         this.context = applicationContext; 
  21.     } 
  22.  
  23.  
  24.     @GetMapping(value = "/test"
  25.     public String test(){ 
  26.         log.info("test --- start"); 
  27.         try { 
  28.             Thread.sleep(100000); 
  29.         } catch (InterruptedException e) { 
  30.             e.printStackTrace(); 
  31.         } 
  32.         log.info("test --- end"); 
  33.         return "test"
  34.     } 
  35.  
  36.     /** 
  37.      * 停機 
  38.      */ 
  39.     @PostMapping(value = "shutdown"
  40.     public void shutdown(){ 
  41.         ConfigurableApplicationContext cyx = (ConfigurableApplicationContext) context; 
  42.         cyx.close(); 
  43.     } 

重點在:cyx.close(); 為什么他能停止 SpringBoot 項目呢?請看源碼:

  1. public void close() { 
  2.         synchronized(this.startupShutdownMonitor) { 
  3.             this.doClose(); 
  4.             if (this.shutdownHook != null) { 
  5.                 try { 
  6.                     Runtime.getRuntime().removeShutdownHook(this.shutdownHook); 
  7.                 } catch (IllegalStateException var4) { 
  8.                 } 
  9.             } 
  10.  
  11.         } 
  12.     } 

程序在啟動的時候向 JVM 注冊了一個關閉鉤子,我們在執行 colse 方法的時候會刪除這個關閉鉤子,JVM 就會知道這是需要停止服務。

我們看測試結果:

很明顯,他也出發了線程的 interrupt 方法導致線程報錯,原理和 kill -15 差不多。

③actuator

這種方式是通過引入依賴的方式停止服務,actuator 提供了很多接口,比如健康檢查,基本信息等等,我們也可以使用他來優雅的停機。

引入依賴:

  1. <dependency> 
  2.             <groupId>org.springframework.boot</groupId> 
  3.             <artifactId>spring-boot-starter-actuator</artifactId> 
  4.         </dependency> 

application.yml:

  1. server: 
  2.   port: 9988 
  3.  
  4. management: 
  5.   endpoints: 
  6.     web: 
  7.       exposure: 
  8.         include: shutdown 
  9.   endpoint: 
  10.     shutdown: 
  11.       enabled: true 
  12.   server: 
  13.     port: 8888 

我這里對 actuator 的接口重新給定了一個接口,這樣可提高安全性,下面我們來測試一下:

  1. @RequestMapping(value = "/test",method = RequestMethod.GET) 
  2.     public String test(){ 
  3.         System.out.println("test --- start"); 
  4.         try { 
  5.             Thread.sleep(10000); 
  6.         } catch (InterruptedException e) { 
  7.             e.printStackTrace(); 
  8.         } 
  9.         System.out.println("test --- end"); 
  10.         return "hello"
  11.     } 

在請求 test 途中停止服務:

我們發現發送停止服務請求之后還給我們返回了提示信息,很人性化,我們看看控制臺:

test — end 被執行了,不過在停止線程池的時候還是調用了線程的 interrupt 方法,導致 sleep 報錯,這三種方式都可以比較優雅的停止 SpringBoot 服務。

如果我項目中存在線程休眠,我希望 10 秒以后再停止服務可以嗎?肯定是可以的,我們只需要稍微做點修改就可以了。

新增停止 SpringBoot 服務類:ElegantShutdownConfig.java。

  1. package com.ymy.config; 
  2.  
  3. import org.apache.catalina.connector.Connector; 
  4. import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer; 
  5. import org.springframework.context.ApplicationListener; 
  6. import org.springframework.context.event.ContextClosedEvent; 
  7.  
  8. import java.util.concurrent.Executor; 
  9. import java.util.concurrent.ThreadPoolExecutor; 
  10. import java.util.concurrent.TimeUnit; 
  11.  
  12. public class ElegantShutdownConfig implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> { 
  13.  
  14.     private volatile Connector connector; 
  15.     private final int waitTime = 10; 
  16.  
  17.     @Override 
  18.     public void customize(Connector connector) { 
  19.         this.connector = connector; 
  20.     } 
  21.  
  22.     @Override 
  23.     public void onApplicationEvent(ContextClosedEvent event) { 
  24.         connector.pause(); 
  25.         Executor executor = connector.getProtocolHandler().getExecutor(); 
  26.         if (executor instanceof ThreadPoolExecutor) { 
  27.             try { 
  28.                 ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; 
  29.                 threadPoolExecutor.shutdown(); 
  30.                 if (!threadPoolExecutor.awaitTermination(waitTime, TimeUnit.SECONDS)) { 
  31.                     System.out.println("請嘗試暴力關閉"); 
  32.                 } 
  33.             } catch (InterruptedException ex) { 
  34.                 System.out.println("異常了"); 
  35.                 Thread.currentThread().interrupt(); 
  36.             } 
  37.         } 
  38.  
  39.     } 

在啟動類中加入 bean:

  1. package com.ymy; 
  2.  
  3. import com.ymy.config.ElegantShutdownConfig; 
  4. import lombok.extern.slf4j.Slf4j; 
  5. import org.apache.catalina.connector.Connector; 
  6. import org.springframework.boot.SpringApplication; 
  7. import org.springframework.boot.autoconfigure.SpringBootApplication; 
  8. import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer; 
  9. import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; 
  10. import org.springframework.boot.web.servlet.server.ServletWebServerFactory; 
  11. import org.springframework.context.ApplicationListener; 
  12. import org.springframework.context.ConfigurableApplicationContext; 
  13. import org.springframework.context.annotation.Bean; 
  14. import org.springframework.context.event.ContextClosedEvent; 
  15.  
  16. import java.util.concurrent.Executor; 
  17. import java.util.concurrent.ThreadPoolExecutor; 
  18. import java.util.concurrent.TimeUnit; 
  19.  
  20. @SpringBootApplication 
  21. public class ShutdownServerApplication { 
  22.  
  23.     public static void main(String[] args) { 
  24.         ConfigurableApplicationContext run = SpringApplication.run(ShutdownServerApplication.class, args); 
  25.         run.registerShutdownHook(); 
  26.     } 
  27.  
  28.  
  29.     @Bean 
  30.     public ElegantShutdownConfig elegantShutdownConfig() { 
  31.         return new ElegantShutdownConfig(); 
  32.     } 
  33.  
  34.     @Bean 
  35.     public ServletWebServerFactory servletContainer() { 
  36.         TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(); 
  37.         tomcat.addConnectorCustomizers(elegantShutdownConfig()); 
  38.         return tomcat; 
  39.     } 

這樣我們就配置好了,我們再來測試一遍,test 的接口還是休眠 10 秒:

我們發現這次沒有報錯了,他是等待了一段時間之后再結束的線程池,這個時間就是我們在 ElegantShutdownConfig 類中配置的 waitTime。

那可能你會有疑問了,JVM 沒有立即停止,那這個時候在有請求會發生什么呢?如果關閉的時候有新的請求,服務將不在接收此請求。

數據備份操作

如果我想在服務停止的時候做點備份操作啥的,應該怎么做呢?其實很簡單在你要執行的方法上添加一個注解即可:@PreDestroy。

  • Destroy:消滅、毀滅。
  • pre:前綴縮寫。

所以合在一起的意思就是在容器停止之前執行一次,你可以在這里面做備份操作,也可以做記錄停機時間等。

新增服務停止備份工具類:DataBackupConfig.java。

  1. package com.ymy.config; 
  2.  
  3. import org.springframework.context.annotation.Configuration; 
  4.  
  5. import javax.annotation.PreDestroy; 
  6.  
  7. @Configuration 
  8. public class DataBackupConfig { 
  9.  
  10.     @PreDestroy 
  11.     public  void backData(){ 
  12.  
  13.         System.out.println("正在備份數據。。。。。。。。。。。"); 
  14.     } 

我們再來測試然后打印控制臺日志:

[[401385]]

作者:流星007

編輯:陶家龍

出處:http://45dwz.com/GrTFl

圖片

 

責任編輯:姜華 來源: 51CTO技術棧
相關推薦

2021-05-21 13:10:17

kill -9微服務Java

2021-02-04 11:30:06

CTOkill -9Linux

2025-08-04 01:55:00

2025-11-03 04:00:00

2025-05-19 04:00:00

2025-08-13 03:00:00

2020-12-02 11:18:50

print調試代碼Python

2020-12-04 10:05:00

Pythonprint代碼

2022-04-14 11:17:41

MySQL字符配置

2021-06-09 06:41:11

OFFSETLIMIT分頁

2020-12-15 08:06:45

waitnotifyCondition

2021-01-29 11:05:50

PrintPython代碼

2020-12-03 09:05:38

SQL代碼方案

2023-10-26 16:33:59

float 布局前段CSS

2020-07-17 07:15:38

數據庫ID代碼

2022-01-27 07:48:37

虛擬項目Django

2024-12-26 07:47:20

2024-06-12 13:54:37

編程語言字符串代碼

2019-03-12 14:48:29

路由器XBOXPS4

2022-10-27 21:34:28

數據庫機器學習架構
點贊
收藏

51CTO技術棧公眾號

国产精品99久久99久久久二8| 欧美美女喷水视频| 欧美二区三区在线| 在线观看av大片| 国产精品jizz在线观看美国| 亚洲精品国产精品久久清纯直播| 欧美三级理论片| 在线黄色网页| 国产亚洲精品久| 91超碰在线免费观看| 国产精品久久久久久久妇| 久久在线电影| 亚洲精品久久久久久久久久久| 免费看国产黄色片| 91超碰在线免费| 亚洲欧洲av一区二区三区久久| 国产原创精品| 99精品免费观看| 日本色综合中文字幕| 国产免费人做人爱午夜视频| 波多野结衣在线观看视频| 欧美在线1区| 一区二区中文字幕| 岛国精品一区二区三区| 国产福利亚洲| 91久久免费观看| 国产二区视频在线| 污污的视频在线观看| 国产女人18水真多18精品一级做| 国产精品综合久久久久久| ,一级淫片a看免费| 日韩高清一级片| 精品丰满少妇一区二区三区| 亚洲视频三区| 欧美二区在线观看| 超碰超碰在线观看| 国产精品欧美一区二区| caopeng视频| 台湾佬综合网| 亚洲国产精品99| 国产精品色呦| 国产视频在线观看一区二区三区| 成人免费看片网站| 国产露脸无套对白在线播放| 日本午夜一本久久久综合| 97在线免费观看| 国产污视频在线看| 亚洲精选91| 91精品国产91久久久| 日韩精品乱码久久久久久| 韩国亚洲精品| 欧美精品福利在线| 国产第一页第二页| 亚洲国产裸拍裸体视频在线观看乱了中文 | 午夜精品一区二区在线观看 | 超碰精品在线| 精品美女一区二区| 逼特逼视频在线观看| 99久久香蕉| 欧美精品一区二区三区高清aⅴ| 久久精品国产99久久99久久久| 国产精品无码久久久久| 欧美日韩免费不卡视频一区二区三区| 韩国日本美国免费毛片| 黄色日韩网站| 91精品久久久久久久99蜜桃| 无套白嫩进入乌克兰美女| 7m精品国产导航在线| 日韩免费在线观看| 手机在线成人av| 亚洲人成亚洲精品| 伊人伊成久久人综合网站| 粉嫩精品久久99综合一区| 91麻豆精品国产91久久久平台 | 亚洲国产成人久久| 国产精品无码一区二区三区| 欧美精品一区二区三区精品| 日韩在线精品一区| 久久精品www人人爽人人| 日韩视频免费| 国产精品免费视频久久久| 国产精品国产三级国产aⅴ| 国产一区二区三区香蕉| 国产自产在线视频一区| 国产黄色在线| 一区二区三区 在线观看视频| 毛片在线视频播放| 日韩国产大片| 亚洲国产天堂久久综合| 夫妇交换中文字幕| 欧美日一区二区在线观看 | 一区二区三区四区欧美日韩| 亚洲夜夜综合| 在线观看亚洲成人| 欧美性猛交乱大交| 国产精品视频一区二区三区四蜜臂| 中文字幕日韩综合av| 久久亚洲成人av| 日韩电影在线一区二区| 成人片在线免费看| 在线观看国产原创自拍视频| 亚洲国产色一区| 爱情岛论坛亚洲首页入口章节| 99亚洲乱人伦aⅴ精品| 一本一本久久a久久精品牛牛影视 一本色道久久综合亚洲精品小说 一本色道久久综合狠狠躁篇怎么玩 | 999热视频| 国产中文在线观看| 午夜欧美视频在线观看| 午夜福利123| 精品久久美女| 97香蕉久久夜色精品国产| 国产乱淫a∨片免费观看| 91色视频在线| 成人小视频在线观看免费| 国产精品久久久久久吹潮| 亚洲精品国产免费| 久久精品99国产精| 九色综合狠狠综合久久| 欧美一区国产一区| 成人免费网站观看| 91精品国产免费久久综合| 久久久亚洲av波多野结衣| 亚洲视频久久| 91pron在线| 麻豆网站在线| 欧美日本不卡视频| 亚洲天堂最新地址| 久久精品123| 久久久7777| 国产免费拔擦拔擦8x在线播放 | 欧美日韩国产精品专区| 国产精品嫩草69影院| 亚洲激情中文| 91精品在线看| 精品麻豆一区二区三区 | 天天操狠狠操夜夜操| 久久综合色占| 热门国产精品亚洲第一区在线| 全国男人的天堂网| 无吗不卡中文字幕| 国产精品福利导航| 国产精品日韩精品欧美精品| 国产无套精品一区二区| 男人添女人下部高潮视频在线观看 | 欧美成人精品在线播放| 国产精品久久久久久久久久久久久久久久| 国产区在线观看成人精品 | 日韩黄色av网站| www.av麻豆| 久久综合久久综合久久综合| 日本www在线播放| 亚洲人成网77777色在线播放| 55夜色66夜色国产精品视频| 三级黄视频在线观看| 日韩欧美中文在线| 美女被到爽高潮视频| 视频一区二区三区在线| 欧美日韩国产精品一区二区| 国产韩日精品| 日韩在线观看视频免费| 国产高清视频免费| 亚洲午夜在线视频| 亚洲国产精品无码久久久久高潮| 一区二区激情| 亚洲第一综合| 久久亚洲精精品中文字幕| 欧美第一页在线| 婷婷在线免费视频| 一本到高清视频免费精品| a资源在线观看| 国产在线麻豆精品观看| 人妻无码久久一区二区三区免费| 私拍精品福利视频在线一区| 国产精品免费一区豆花| 国产在线观看91| 亚洲高清在线观看| 中文字幕第99页| 亚洲影院在线观看| 久久久亚洲av波多野结衣| 久久国产综合精品| 男女激情免费视频| jizzjizz欧美69巨大| 亚洲精品日韩av| 高清不卡av| 蜜臀久久99精品久久久无需会员| 欧美 日韩 综合| 91久久精品一区二区三区| 欧美国产在线看| 国产日韩av一区| 欧美激情一区二区三区p站| 日韩中文字幕麻豆| 真实国产乱子伦对白视频| 亚洲调教一区| 97人人香蕉| 九色成人搞黄网站| 国语自产精品视频在线看一大j8 | 午夜精品一区二区三区国产 | 人妻无码一区二区三区| 狠狠狠色丁香婷婷综合激情| 国产精品免费观看久久| 综合激情一区| 色噜噜狠狠一区二区三区| 99精品在免费线中文字幕网站一区| 国产成人久久久| 金瓶狂野欧美性猛交xxxx| 中国china体内裑精亚洲片| 欧美 日韩 人妻 高清 中文| 欧美精品在线观看一区二区| av黄色在线播放| 亚洲制服欧美中文字幕中文字幕| 免费91在线观看| 久久伊人蜜桃av一区二区| 在线播放免费视频| 蜜臀av一级做a爰片久久| 久久综合色视频| 欧美激情五月| 日韩人妻精品一区二区三区| 日韩精品一区二区久久| 久久五月天婷婷| 国产精品sss在线观看av| 国产在线观看精品| 123成人网| 国产97在线亚洲| 伊人久久av| 97超碰蝌蚪网人人做人人爽 | 亚洲成精国产精品女| 欧美老熟妇一区二区三区| 国产精品久久久久天堂| 怡红院一区二区三区| 久久影院午夜片一区| 国产精品无码永久免费不卡| jlzzjlzz亚洲日本少妇| 美女露出粉嫩尿囗让男人桶| 国产在线不卡一卡二卡三卡四卡| 鲁一鲁一鲁一鲁一av| 日韩黄色免费电影| 中文字幕国产传媒| 日本成人超碰在线观看| 不卡av免费在线| 蜜桃视频一区二区三区在线观看| 欧美 日韩 国产 激情| 日韩主播视频在线| 国产精品拍拍拍| 蜜桃一区二区三区在线| 三上悠亚av一区二区三区| 蜜乳av一区二区| 15—17女人毛片| 久久精品国产网站| 中文字幕亚洲影院| 国产精品一区二区在线看| 熟妇无码乱子成人精品| 国产麻豆精品95视频| 在线观看欧美一区二区| 国产a久久麻豆| 日本黄色录像片| 久久五月婷婷丁香社区| 国产午夜福利一区| 国产精品传媒入口麻豆| 蜜臀久久精品久久久用户群体| 樱桃视频在线观看一区| 国产一级特黄aaa大片| 狠狠久久亚洲欧美专区| 成年人视频免费| 69堂成人精品免费视频| 亚洲欧美另类视频| 日韩精品一区二区三区第95| 精品美女视频在线观看免费软件| 一区二区欧美在线| 91黄色在线| 97人人模人人爽人人喊中文字| 少妇在线看www| 国产日韩换脸av一区在线观看| 9999在线精品视频| 国产免费一区二区| 超碰成人久久| 特级西西人体www高清大胆| 亚洲高清资源| 国产超碰在线播放| 国产精品原创巨作av| 国产精品300页| 中文字幕在线不卡| 91av在线免费视频| 欧美日韩精品是欧美日韩精品| 精品美女www爽爽爽视频| 精品中文视频在线| 精品176二区| 欧美专区福利在线| 精品中文在线| 日韩高清国产精品| 亚洲性色视频| 91国内在线播放| 久久蜜桃av一区精品变态类天堂 | 欧美老女人第四色| 五月激情丁香婷婷| 日韩视频在线一区| 一个人看的www视频在线免费观看| 91精品久久久久久久久久另类| 国产精品色呦| 中文字幕第50页| 日韩电影在线免费看| www.男人天堂| 亚洲欧美一区二区不卡| 精品人妻一区二区三区免费看| 欧美一区二区三区四区久久| 免费人成黄页在线观看忧物| 久久久久久久久久久91| 久久99久久久精品欧美| 久久综合狠狠综合久久综青草| 亚洲成人99| 在线视频日韩一区| 2020国产精品| 日韩精品手机在线| 日韩欧美在线网站| 午夜免费视频在线国产| 热草久综合在线| 欧美成人午夜77777| 免费的一级黄色片| 久久成人免费网| 国产精品成人在线视频| 色婷婷av一区| 天天影院图片亚洲| 97久久国产精品| 成人线上播放| 欧美午夜精品在线| 亚洲精品极品| 色一情一区二区三区| 99久久国产综合色|国产精品| 国产精品国产精品88| 在线亚洲高清视频| 欧美性孕妇孕交| 97久久超碰福利国产精品…| 视频一区日韩| 三年中国中文在线观看免费播放 | 亚洲少妇18p| 中文字幕视频一区| 中文字幕第315页| 亚洲天堂2020| 日韩天堂在线| 色吧亚洲视频| 日韩综合在线视频| 性欧美精品男男| 欧美性极品少妇| 91在线品视觉盛宴免费| 国产精品一区二区3区| 日韩在线看片| 做a视频在线观看| 综合久久国产九一剧情麻豆| 国产乱淫a∨片免费观看| 欧美精品免费在线观看| 亚洲一区二区电影| 97免费视频观看| 成人h精品动漫一区二区三区| 亚洲国产精一区二区三区性色| 亚洲国产黄色片| 羞羞影院欧美| 亚洲视频小说| 国产成人av资源| 国产a∨精品一区二区三区仙踪林| 日韩av影视综合网| 久久99久久99精品免观看软件| 亚洲开发第一视频在线播放| 狠狠色狠狠色综合日日91app| 国产在线一卡二卡| 亚洲第一精品自拍| 在线成人视屏| 日本一道在线观看| 99精品视频在线观看| 日韩在线播放中文字幕| 视频在线观看99| 4438全国亚洲精品观看视频| 中文字幕无码精品亚洲35| 久久婷婷成人综合色| 在线播放国产一区| 欧美激情视频网址| 蜜桃tv一区二区三区| av在线免费看片| 亚洲成av人片一区二区三区 | 国产婷婷一区二区三区久久| 欧美片一区二区三区| 加勒比久久高清| 国产一区二区在线免费播放| 亚洲激情综合网| 欧美女优在线观看| 91亚洲精品一区二区| 国产精品美女久久久| 婷婷伊人五月天| 日韩毛片在线观看| 国产aⅴ精品一区二区四区| 男人插女人视频在线观看| 中文av字幕一区| 日韩一级中文字幕| 国产日韩欧美91| 国产精品女主播一区二区三区| 亚洲女人久久久| 精品无码久久久久久国产| 国产精品久久久久久av公交车| www黄色日本| 亚洲精品久久久蜜桃| 国产精品免费播放| 国产伦精品一区二区三毛|