SpringBoot 優雅重啟


由於springboot項目是打成jar包運行,所以在維護過程中需要不斷更新;每次都是上傳jar,執行 ps -ef|grep java 命令查找java進程,kill pid,nohup java -jar test.jar ;太麻煩了,所以就做了重啟腳本;

 

1,在項目中添加shutdown配置類

  Spring Boot 1.X

 1 import java.util.concurrent.Executor;  2 import java.util.concurrent.ThreadPoolExecutor;  3 import java.util.concurrent.TimeUnit;  4 import org.apache.catalina.connector.Connector;  5 import org.slf4j.Logger;  6 import org.slf4j.LoggerFactory;  7 import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;  8 import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;  9 import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer; 10 import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; 11 import org.springframework.context.ApplicationListener; 12 import org.springframework.context.annotation.Bean; 13 import org.springframework.context.annotation.Configuration; 14 import org.springframework.context.event.ContextClosedEvent; 15 /** 16  * Spring Boot1.X Tomcat容器優雅停機 17  * 18 */ 19 @Configuration 20 public class ShutdownConfig { 21 /** 22  * 用於接受shutdown事件 23  * @return 24 */ 25  @Bean 26 public GracefulShutdown gracefulShutdown() { 27 return new GracefulShutdown(); 28  } 29 /** 30  * 用於注入 connector 31  * @return 32 */ 33  @Bean 34 public EmbeddedServletContainerCustomizer tomcatCustomizer() { 35 return new EmbeddedServletContainerCustomizer() { 36  @Override 37 public void customize(ConfigurableEmbeddedServletContainer container) { 38 if (container instanceof TomcatEmbeddedServletContainerFactory) { 39  ((TomcatEmbeddedServletContainerFactory) container).addConnectorCustomizers(gracefulShutdown()); 40  } 41  } 42  }; 43  } 44 private static class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> { 45 private static final Logger log = LoggerFactory.getLogger(GracefulShutdown.class); 46 private volatile Connector connector; 47 private final int waitTime = 120; 48  @Override 49 public void customize(Connector connector) { 50 this.connector = connector; 51  } 52  @Override 53 public void onApplicationEvent(ContextClosedEvent event) { 54 this.connector.pause(); 55 Executor executor = this.connector.getProtocolHandler().getExecutor(); 56 if (executor instanceof ThreadPoolExecutor) { 57 try { 58 ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; 59 log.info("shutdown start"); 60  threadPoolExecutor.shutdown(); 61 log.info("shutdown end"); 62 if (!threadPoolExecutor.awaitTermination(waitTime, TimeUnit.SECONDS)) { 63 log.info("Tomcat 進程在" + waitTime + "秒內無法結束,嘗試強制結束"); 64  } 65 log.info("shutdown success"); 66 } catch (InterruptedException ex) { 67  Thread.currentThread().interrupt(); 68  } 69  } 70  } 71  } 72 }

  Spring Boot 2.X

  

  1 import java.util.concurrent.Executor;
 2 import java.util.concurrent.ThreadPoolExecutor;  3 import java.util.concurrent.TimeUnit;  4 import org.apache.catalina.connector.Connector;  5 import org.slf4j.Logger;  6 import org.slf4j.LoggerFactory;  7 import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;  8 import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;  9 import org.springframework.boot.web.servlet.server.ServletWebServerFactory; 10 import org.springframework.context.ApplicationListener; 11 import org.springframework.context.annotation.Bean; 12 import org.springframework.context.annotation.Configuration; 13 import org.springframework.context.event.ContextClosedEvent; 14 /** 15  * Spring Boot2.X Tomcat容器優雅停機 16  * 17 */ 18 @Configuration 19 public class ShutdownConfig { 20 /** 21  * 用於接受shutdown事件 22  * @return 23 */ 24  @Bean 25 public GracefulShutdown gracefulShutdown() { 26 return new GracefulShutdown(); 27  } 28  @Bean 29 public ServletWebServerFactory servletContainer() { 30 TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(); 31  tomcat.addConnectorCustomizers(gracefulShutdown()); 32 return tomcat; 33  } 34 private static class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> { 35 private static final Logger log = LoggerFactory.getLogger(GracefulShutdown.class); 36 private volatile Connector connector; 37 private final int waitTime = 120; 38  @Override 39 public void customize(Connector connector) { 40 this.connector = connector; 41  } 42  @Override 43 public void onApplicationEvent(ContextClosedEvent event) { 44 this.connector.pause(); 45 Executor executor = this.connector.getProtocolHandler().getExecutor(); 46 if (executor instanceof ThreadPoolExecutor) { 47 try { 48 ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; 49 log.info("shutdown start"); 50  threadPoolExecutor.shutdown(); 51 log.info("shutdown end"); 52 if (!threadPoolExecutor.awaitTermination(waitTime, TimeUnit.SECONDS)) { 53 log.info("Tomcat 進程在" + waitTime + "秒內無法結束,嘗試強制結束"); 54  } 55 log.info("shutdown success"); 56 } catch (InterruptedException ex) { 57  Thread.currentThread().interrupt(); 58  } 59  } 60  } 61  } 62 }

 

2,重啟服務腳本

 1 #!/bin/sh  2 JAVA_OPTS='-Xms128m -Xmx512m -XX:NewSize=128m -XX:MaxNewSize=512m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m -XX:NewRatio=2 -XX:MaxTenuringThreshold=8 -XX:+DisableExplicitGC'  3 RESOURCE_NAME=/home/test-0.0.1-SNAPSHOT.jar  4 LOG_NAME=/home/test.log  5 MAX_TIMEOUT=20  6  7 tpid=`ps -ef|grep $RESOURCE_NAME|grep -v grep|grep -v kill|awk '{print $2}'`  8  9 if [ ${tpid} ]; then 10 echo 'Stop Process...' 11 kill -15 $tpid 12 fi 13 14 for((i=0;i<$MAX_TIMEOUT;i++)) 15 do 16 sleep 1 17 tpid=`ps -ef|grep $RESOURCE_NAME|grep -v grep|grep -v kill|awk '{print $2}'` 18 if [ ${tpid} ]; then 19 echo 'App Stoping...' 20 else 21 break 22  fi 23 done 24 25 if [ ${tpid} ]; then 26 echo 'Kill Process!' 27 kill -9 $tpid 28 else 29 echo 'Stop Success!' 30 fi 31 32 tpid=`ps -ef|grep $RESOURCE_NAME|grep -v grep|grep -v kill|awk '{print $2}'` 33 34 if [ ${tpid} ]; then 35 echo 'App is running.' 36 else 37 echo 'App is NOT running.' 38 fi 39 40 rm -f tpid 41 42 echo 'App is Starting...' 43 nohup java $JAVA_OPTS -jar $RESOURCE_NAME >$LOG_NAME 2>&1 & 44 echo $! > tpid 45 echo Start Success!

 

3,測試

  編寫簡單的接口,在接口中等待,然后執行腳本停止項目,如果正常的話會輸出服務停止中,等到你的接口執行完成,進程才會消失掉,但是如果超過了你配置的等待時間就會強行退出。

  

 1 @RequestMapping("/test")  2 public String test() throws InterruptedException  3  {  4  5 log.info("接口開始執行...");  6 log.info("接口執行中...");  7 final CountDownLatch latch = new CountDownLatch(12);  8 ListeningExecutorService pool = null;  9 10 pool = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1)); 11 12 for (int i = 0; i < 12; i++) { 13 ListenableFuture<String> listenableFuture = pool.submit(() -> { 14 15 Thread.sleep(1000); 16 log.info("Thread Name:{}", Thread.currentThread().getName()); 17 return "OK"; 18  }); 19 20 Futures.addCallback(listenableFuture, new FutureCallback<String>() 21  { 22 public void onSuccess(String orderList) 23  { 24  latch.countDown(); 25 log.info("{}--{}", orderList, Thread.currentThread().getName()); 26  } 27 28 public void onFailure(Throwable throwable) 29  { 30  latch.countDown(); 31  System.out.println(throwable.getMessage()); 32  } 33  }); 34  } 35 36  latch.await(); 37  pool.shutdown(); 38 39 log.info("接口執行完成..."); 40 log.info("系統正常退出..."); 41 return "OK"; 42 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM