码迷,mamicode.com
首页 > 编程语言 > 详细

SpringBoot 优雅重启

时间:2018-07-12 20:03:25      阅读:261      评论:0      收藏:0      [点我收藏+]

标签:时间   meta   xpl   ping   throwable   connect   actor   callback   one   

  由于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     }

 

SpringBoot 优雅重启

标签:时间   meta   xpl   ping   throwable   connect   actor   callback   one   

原文地址:https://www.cnblogs.com/hpxiaokang/p/9300933.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!