1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Spring Boot 優(yōu)雅停止服務(wù)的幾種方法~

        共 7560字,需瀏覽 16分鐘

         ·

        2021-04-27 23:48


        作者 | 黃青石

        來(lái)源 | cnblogs.com/huangqingshi/p/11370291.html


        最近突然想到了優(yōu)雅停止 SpringBoot 服務(wù)問(wèn)題,在使用 SpringBoot 的時(shí)候,都要涉及到服務(wù)的停止和啟動(dòng),當(dāng)我們停止服務(wù)的時(shí)候,很多時(shí)候大家都是kill -9 直接把程序進(jìn)程殺掉,這樣程序不會(huì)執(zhí)行優(yōu)雅的關(guān)閉。而且一些沒(méi)有執(zhí)行完的程序就會(huì)直接退出。

        我們很多時(shí)候都需要安全的將服務(wù)停止,也就是把沒(méi)有處理完的工作繼續(xù)處理完成。比如停止一些依賴的服務(wù),輸出一些日志,發(fā)一些信號(hào)給其他的應(yīng)用系統(tǒng),這個(gè)在保證系統(tǒng)的高可用是非常有必要的。

        那么咱么就來(lái)看一下幾種停止 SpringBoot 的方法。

        第一種

        就是Springboot提供的actuator的功能,它可以執(zhí)行shutdown, health, info等,默認(rèn)情況下,actuator的shutdown是disable的,我們需要打開它。首先引入acturator的maven依賴。
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        然后將shutdown節(jié)點(diǎn)打開,也將/actuator/shutdown暴露web訪問(wèn)也設(shè)置上,除了shutdown之外還有health, info的web訪問(wèn)都打開的話將management.endpoints.web.exposure.include=*就可以。

        將如下配置設(shè)置到application.properties里邊。設(shè)置一下服務(wù)的端口號(hào)為3333。
        server.port=3333
                management.endpoint.shutdown.enabled=true
                management.endpoints.web.exposure.include=shutdown

        接下來(lái),咱們創(chuàng)建一個(gè)springboot工程,然后設(shè)置一個(gè)bean對(duì)象,配置上PreDestroy方法。這樣在停止的時(shí)候會(huì)打印語(yǔ)句。

        bean的整個(gè)生命周期分為創(chuàng)建、初始化、銷毀,當(dāng)最后關(guān)閉的時(shí)候會(huì)執(zhí)行銷毀操作。在銷毀的方法中執(zhí)行一條輸出日志。
        package com.hqs.springboot.shutdowndemo.bean;

        import javax.annotation.PreDestroy;

        /**
         * @author huangqingshi
         * @Date 2019-08-17
         */

        public class TerminateBean {

            @PreDestroy
            public void preDestroy() {
                System.out.println("TerminalBean is destroyed");
            }

        }
        做一個(gè)configuration,然后提供一個(gè)獲取bean的方法,這樣該bean對(duì)象會(huì)被初始化。
        package com.hqs.springboot.shutdowndemo.config;

        import com.hqs.springboot.shutdowndemo.bean.TerminateBean;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;

        /**
         * @author huangqingshi
         * @Date 2019-08-17
         */

        @Configuration
        public class ShutDownConfig {

            @Bean
            public TerminateBean getTerminateBean() {
                return new TerminateBean();
            }

        }
        在啟動(dòng)類里邊輸出一個(gè)啟動(dòng)日志,當(dāng)工程啟動(dòng)的時(shí)候,會(huì)看到啟動(dòng)的輸出,接下來(lái)咱們執(zhí)行停止命令。
        curl -X POST http://localhost:3333/actuator/shutdown
        以下日志可以輸出啟動(dòng)時(shí)的日志打印和停止時(shí)的日志打印,同時(shí)程序已經(jīng)停止。是不是比較神奇。

        第二種

        比較簡(jiǎn)單,獲取程序啟動(dòng)時(shí)候的context,然后關(guān)閉主程序啟動(dòng)時(shí)的context。這樣程序在關(guān)閉的時(shí)候也會(huì)調(diào)用PreDestroy注解。如下方法在程序啟動(dòng)十秒后進(jìn)行關(guān)閉。
        /* method 2: use ctx.close to shutdown all application context */
                ConfigurableApplicationContext ctx = SpringApplication.run(ShutdowndemoApplication.classargs);

                try {
                TimeUnit.SECONDS.sleep(10);

                } catch (InterruptedException e) {
                e.printStackTrace();
                }

                ctx.close();

        第三種

        在springboot啟動(dòng)的時(shí)候?qū)⑦M(jìn)程號(hào)寫入一個(gè)app.pid文件,生成的路徑是可以指定的,可以通過(guò)命令 cat /Users/huangqingshi/app.id | xargs kill 命令直接停止服務(wù),這個(gè)時(shí)候bean對(duì)象的PreDestroy方法也會(huì)調(diào)用的。

        這種方法大家使用的比較普遍。寫一個(gè)start.sh用于啟動(dòng)springboot程序,然后寫一個(gè)停止程序?qū)⒎?wù)停止。
        /* method 3 : generate a pid in a specified path, while use command to shutdown pid :
                    'cat /Users/huangqingshi/app.pid | xargs kill' */

                SpringApplication application = new SpringApplication(ShutdowndemoApplication.class);
                application.addListeners(new ApplicationPidFileWriter("/Users/huangqingshi/app.pid"));
                application.run();

        第四種

        通過(guò)調(diào)用一個(gè)SpringApplication.exit()方法也可以退出程序,同時(shí)將生成一個(gè)退出碼,這個(gè)退出碼可以傳遞給所有的context。


        這個(gè)就是一個(gè)JVM的鉤子,通過(guò)調(diào)用這個(gè)方法的話會(huì)把所有PreDestroy的方法執(zhí)行并停止,并且傳遞給具體的退出碼給所有Context。


        通過(guò)調(diào)用System.exit(exitCode)可以將這個(gè)錯(cuò)誤碼也傳給JVM。程序執(zhí)行完后最后會(huì)輸出:Process finished with exit code 0,給JVM一個(gè)SIGNAL。

        /* method 4: exit this application using static method */
                ConfigurableApplicationContext ctx = SpringApplication.run(ShutdowndemoApplication.classargs);
                exitApplication(ctx);
        public static void exitApplication(ConfigurableApplicationContext context) {
                int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);

                System.exit(exitCode);
                }

        第五種

        自己寫一個(gè)Controller,然后將自己寫好的Controller獲取到程序的context,然后調(diào)用自己配置的Controller方法退出程序。


        通過(guò)調(diào)用自己寫的/shutDownContext方法關(guān)閉程序:curl -X POST http://localhost:3333/shutDownContext。

        package com.hqs.springboot.shutdowndemo.controller;

        import org.springframework.beans.BeansException;
        import org.springframework.context.ApplicationContext;
        import org.springframework.context.ApplicationContextAware;
        import org.springframework.context.ConfigurableApplicationContext;
        import org.springframework.web.bind.annotation.GetMapping;
        import org.springframework.web.bind.annotation.PostMapping;
        import org.springframework.web.bind.annotation.RestController;

        /**
         * @author huangqingshi
         * @Date 2019-08-17
         */

        @RestController
        public class ShutDownController implements ApplicationContextAware {

            private ApplicationContext context;

            @PostMapping("/shutDownContext")
            public String shutDownContext() {
                ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) context;
                ctx.close();
                return "context is shutdown";
            }

            @GetMapping("/")
            public String getIndex() {
                return "OK";
            }

            @Override
            public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
                context = applicationContext;
            }
        }
        好了,springboot的優(yōu)雅關(guān)閉方法也都實(shí)現(xiàn)好了,也有同學(xué)問(wèn),如何暴力停止呢,簡(jiǎn)單,直接kill -9 相應(yīng)的PID即可。

        總結(jié)一下

        以上這幾種方法實(shí)現(xiàn)的話比較簡(jiǎn)單,但是真實(shí)工作中還需要考慮的點(diǎn)還很多,比如需要保護(hù)暴露的點(diǎn)不被別人利用,一般要加一些防火墻,或者只在內(nèi)網(wǎng)使用,保證程序安全。

        在真實(shí)的工作中的時(shí)候第三種比較常用,程序中一般使用內(nèi)存隊(duì)列或線程池的時(shí)候最好要優(yōu)雅的關(guān)機(jī),將內(nèi)存隊(duì)列沒(méi)有處理的保存起來(lái)或線程池中沒(méi)處理完的程序處理完。

        但是因?yàn)橥C(jī)的時(shí)候比較快,所以停服務(wù)的時(shí)候最好不要處理大量的數(shù)據(jù)操作,這樣會(huì)影響程序停止。

        好了,大家覺(jué)得還沒(méi)看全的話,可以訪問(wèn)我的GIT代碼:
        https://github.com/stonehqs/shutdowndemo.git 。

        1、全網(wǎng)最全 Java 日志框架適配方案!還有誰(shuí)不會(huì)?
        2、Chrome瀏覽器最新高危漏洞曝光!升級(jí)最新版也沒(méi)用~
        3、Spring中毒太深,離開Spring我居然連最基本的接口都不會(huì)寫了
        4、黑客用GitHub服務(wù)器挖礦,三天跑了3萬(wàn)個(gè)任務(wù),代碼驚現(xiàn)中文
        5、驚呆了,Spring Boot居然這么耗內(nèi)存!你知道嗎?
        6、Gradle真能干掉Maven?今天體驗(yàn)了一把,賊爽!
        7、如何重構(gòu)千行“又臭又長(zhǎng)”的類?IntelliJ IDEA 幾分鐘就搞定!

        點(diǎn)分享

        點(diǎn)收藏

        點(diǎn)點(diǎn)贊

        點(diǎn)在看

        瀏覽 56
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产3级在线观看 | 成欢阁免费视频 | 小受揉h势g短篇h | 一区大宝贝 | 女人被狂躁到高潮视频免费网站 | 欧美一级婬片A片免费有限公司 | 国产精品无码合集 | 我爱大香蕉在线 | 《漂亮的女邻居5》hd | 国产精品久久久久久久久久久易记 |