成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring Boot 實現優雅停機的正確姿勢!

開發 前端
如果暴力的關閉應用程序,比如通過kill -9 <pid>命令強制直接關閉應用程序進程,可能會導致正在執行的任務數據丟失或者錯亂,也可能會導致任務所持有的全局資源等不到釋放,比如當前任務持有 redis 的鎖,并且沒有設置過期時間,當任務突然被終止并且沒有主動釋放鎖,會導致其他進程因無法獲取鎖而不能處理業務。

一、背景介紹

什么叫優雅停機?

簡單的說,就是向應用進程發出停止指令之后,能保證正在執行的業務操作不受影響,直到操作運行完畢之后再停止服務。應用程序接收到停止指令之后,會進行如下操作:

  • 1.停止接收新的訪問請求
  • 2.正在處理的請求,等待請求處理完畢;對于內部正在執行的其他任務,比如定時任務、mq 消費等等,也要等當前正在執行的任務執行完畢,并且不再啟動新的任務
  • 3.當應用準備關閉的時候,按需向外發出信號,告知其他應用服務準備接手,以保證服務高可用

如果暴力的關閉應用程序,比如通過kill -9 <pid>命令強制直接關閉應用程序進程,可能會導致正在執行的任務數據丟失或者錯亂,也可能會導致任務所持有的全局資源等不到釋放,比如當前任務持有 redis 的鎖,并且沒有設置過期時間,當任務突然被終止并且沒有主動釋放鎖,會導致其他進程因無法獲取鎖而不能處理業務。

那么如何在不影響正在執行的業務的情況下,將應用程序安全的進行關閉呢?

二、方案實踐

SpringBoot 官方文檔上,已經告訴開發者只需要實現特定接口即可監聽到項目啟動成功與關閉時的事件,相關接口如下:

  • CommandLineRunner接口:當應用啟動成功后但在開始接受流量之前,會回調此接口的實現類,也可以實現ApplicationRunner接口,工作的方式與CommandLineRunner與之類似
  • DisposableBean接口:當應用正要被銷毀前,會回調此接口的實現類,也可以使用@PreDestroy注解,被標記的方法也會被調用

基于此流程,我們可以創建一個服務監聽類,用于監聽到項目啟動成功與關閉時的回調服務,示例代碼如下:

@Component
public class AppListener implements CommandLineRunner, DisposableBean {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("應用啟動成功,預加載相關數據");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("應用正在關閉,清理相關數據");
    }

}

每一個SpringApplication在啟用的時候,都會向 JVM 注冊一個關閉鉤子shutdown hook,以確保ApplicationContext在退出的時候,通過這個勾子通知 JVM,實現服務正常的關閉,以下介紹的所有關閉服務的方法,都是基于這一原理進行實現的。

2.1方法一:通過Actuator的Endpoint機制關閉服務

使用此方法,需要先添加spring-boot-starter-actuator監控服務依賴包,

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

默認配置下,shutdown端點是關閉的,需要在application.properties里配置里面開啟:

management.endpoint.shutdown.enabled=true

雖然Actuator的端點,支持通過JMX或HTTP進行遠程訪問。而shutdown默認配置下是不支持HTTP進行Web訪問的,所以使用HTTP請求進行關閉時的配置,也需要開啟:

management.endpoints.web.exposure.include=shutdown

最后將SpringBoot服務啟動之后,使用POST請求類型,調用以下接口,即可實現關閉服務!

http://127.0.0.1:8080/actuator/shutdown

圖片圖片

2.2方法二:使用ApplicationContext的close方法關閉服務

如果你不想添加spring-boot-starter-actuator監控服務依賴包來關停服務,也可以使用ApplicationContext的close方法來關停服務,他會自動銷毀bean對象并關停服務。

只需要在應用啟用的時候,獲取ApplicationContext對象,然后在相關的位置調用close方法,就可以關閉服務。

示例代碼如下:

@SpringBootApplication
publicclass Application {

    public static void main(String[] args) {
      ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

      try {
         TimeUnit.SECONDS.sleep(10);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
      //啟動10秒以后,自動關閉
      context.close();
    }
}

當然我們也可以自己寫一個Controller,獲取對應的ApplicationContext對象,通過api操作調用close方法關停服務,示例代碼如下:

@RestController
publicclass ShutdownController implements ApplicationContextAware {

    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }

    /**
     * 關閉服務
     */
    @GetMapping("/shutdown")
    public void shutdownContext() {
        ((ConfigurableApplicationContext) context).close();
    }
}

2.3方法三:監聽服務pid,通過kill方式關閉服務

通過api方式來關停服務,在很多人看來并不安全,因為一旦接口泄漏了,意味著用戶可以隨便請求這個接口來關閉服務,其影響不言而喻,因此很多人建議在服務端,通過其他的方式來關閉服務,比如通過進程命令方式來關停。

在springboot啟動的時候將應用進程 ID 寫入一個app.pid文件,生成的路徑可以指定,然后通過腳本命令方式來關閉服務。

啟動示例代碼如下:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(Application.class);
        application.addListeners(new ApplicationPidFileWriter("/home/app/project1/app.pid"));
        application.run();
    }
}

通過如下命令方式,可以安全的關閉服務。

cat /home/app/project1/app.pid | xargs kill

這種方式,也是目前在linux操作系統中,使用較為普遍的一種解決方案,區別在于實現的方式可能不同,有的不用寫文件,通過其他方式來獲取應用進程 ID。

如果使用kill -9 <pid>的方式關閉服務,服務的監聽器不會收到任何消息,類似于直接強殺應用進程,此方法不可取!

2.4方法四:使用SpringApplication的exit方法關閉服務

通過調用一個SpringApplication.exit()方法也可以安全的退出程序,同時會返回一個退出碼,這個退出碼可以傳遞給所有的context,最后通過調用System.exit()可以將這個錯誤碼也傳給JVM。

示例代碼如下:

@SpringBootApplication
publicclass Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //5秒后,關閉服務
        exitApplication(context);
    }

    public static void exitApplication(ConfigurableApplicationContext context) {
      //獲取退出碼
        int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
        //退出碼傳遞給jvm,安全退出程序
        System.exit(exitCode);
    }

}

三、其他監聽介紹

3.1ApplicationListener

如果有些服務,比如定時任務,我們想在SpringBoot關閉數據源連接池之前,將其關閉,可以通過實現ApplicationListener接口,監聽bean對象的變化情況,在bean對象銷毀之前,執行相關的關閉任務。

示例代碼如下:

@Component
public class JobTaskListener implements ApplicationListener {

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        // 在spring bean容器銷毀之前執行的事件,防止數據庫連接池在任務終止前銷毀
        if (applicationEvent instanceof ContextClosedEvent) {
            System.out.println("關閉相關的定時任務");
        }
    }
}

3.2PreDestroy

上文中,我們提到了實現DisposableBean接口,可以監聽應用關閉前的回調處理,其實在自定義的方法上加@PreDestroy注解,也可以實現相同的效果。

示例代碼如下:

@Component
public class AppDestroyConfig {

    @PreDestroy
    public void PreDestroy(){
        System.out.println("應用程序正在關閉。。。");
    }
}
責任編輯:武曉燕 來源: 潘志的技術筆記
相關推薦

2023-01-30 07:41:43

2021-09-15 16:20:02

Spring BootFilterJava

2024-08-12 10:13:01

2024-08-02 09:15:22

Spring捕捉格式

2024-08-01 09:10:03

2025-02-12 08:07:40

2021-05-08 08:33:00

Rocketmq日志數據源

2021-03-09 13:18:53

加密解密參數

2025-01-17 09:11:51

2022-06-04 12:25:10

解密加密過濾器

2018-11-01 13:38:51

Java中斷停止

2025-02-27 08:30:10

2020-08-05 08:30:25

Spring BootJavaSE代碼

2018-01-11 15:31:39

命令Linux關機

2017-02-23 15:37:44

OptionObject容器

2016-05-09 10:41:03

算法分析開發

2024-12-03 10:59:36

2017-07-10 13:09:45

前端Flexbox

2017-03-16 11:39:33

Openstack源碼姿勢

2024-10-18 08:53:49

SpringMybatis微服務
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕一区二区三区四区五区 | 亚洲综合成人网 | 久久tv在线观看 | 国产亚洲欧美另类一区二区三区 | 黄色在线观看网站 | 日本黄色影片在线观看 | 91精品国产99 | 一级做受毛片免费大片 | 久久99精品久久久久久国产越南 | 亚洲精品视频观看 | 亚洲欧美精品国产一级在线 | 亚洲精品播放 | 欧日韩在线观看 | 日韩中文视频 | 91国内精精品久久久久久婷婷 | 免费看a | 日韩蜜桃视频 | 久久区二区 | 欧美日韩中文字幕在线 | 国产网站在线播放 | 国产精品久久久久久久久久久久冷 | 丝袜一区二区三区 | 欧美成人aaa级毛片在线视频 | 日本高清aⅴ毛片免费 | www.4虎影院 国产999精品久久久影片官网 | 一级网站 | 天天综合日日夜夜 | 欧美福利在线 | 成人欧美一区二区三区黑人孕妇 | 福利久久 | 九九久久久 | 久久国产视频播放 | 日韩靠逼| www.xxxx欧美 | 国产在线精品一区二区三区 | 成人免费网站在线 | www.日韩系列 | 99热播精品 | 伊人av在线播放 | 亚洲国产精品一区二区三区 | 91视频88av |