最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot實(shí)現(xiàn)優(yōu)雅停機(jī)的正確方法

 更新時(shí)間:2023年01月30日 08:58:58   作者:鴨血粉絲Tang  
什么叫優(yōu)雅停機(jī)?就是向應(yīng)用進(jìn)程發(fā)出停止指令之后,能保證正在執(zhí)行的業(yè)務(wù)操作不受影響,直到操作運(yùn)行完畢之后再停止服務(wù)。本文就來和大家聊聊SpringBoot實(shí)現(xiàn)優(yōu)雅停機(jī)的正確姿勢(shì),希望對(duì)大家有所幫助

一、介紹

什么叫優(yōu)雅停機(jī)?

簡單的說,就是向應(yīng)用進(jìn)程發(fā)出停止指令之后,能保證正在執(zhí)行的業(yè)務(wù)操作不受影響,直到操作運(yùn)行完畢之后再停止服務(wù)。應(yīng)用程序接收到停止指令之后,會(huì)進(jìn)行如下操作:

  • 1.停止接收新的訪問請(qǐng)求
  • 2.正在處理的請(qǐng)求,等待請(qǐng)求處理完畢;對(duì)于內(nèi)部正在執(zhí)行的其他任務(wù),比如定時(shí)任務(wù)、mq 消費(fèi)等等,也要等當(dāng)前正在執(zhí)行的任務(wù)執(zhí)行完畢,并且不再啟動(dòng)新的任務(wù)
  • 3.當(dāng)應(yīng)用準(zhǔn)備關(guān)閉的時(shí)候,按需向外發(fā)出信號(hào),告知其他應(yīng)用服務(wù)準(zhǔn)備接手,以保證服務(wù)高可用

如果暴力的關(guān)閉應(yīng)用程序,比如通過kill -9 <pid>命令強(qiáng)制直接關(guān)閉應(yīng)用程序進(jìn)程,可能會(huì)導(dǎo)致正在執(zhí)行的任務(wù)數(shù)據(jù)丟失或者錯(cuò)亂,也可能會(huì)導(dǎo)致任務(wù)所持有的全局資源等不到釋放,比如當(dāng)前任務(wù)持有 redis 的鎖,并且沒有設(shè)置過期時(shí)間,當(dāng)任務(wù)突然被終止并且沒有主動(dòng)釋放鎖,會(huì)導(dǎo)致其他進(jìn)程因無法獲取鎖而不能處理業(yè)務(wù)。

那么如何在不影響正在執(zhí)行的業(yè)務(wù)的情況下,將應(yīng)用程序安全的進(jìn)行關(guān)閉呢?

二、方案實(shí)踐

SpringBoot 官方文檔上,已經(jīng)告訴開發(fā)者只需要實(shí)現(xiàn)特定接口即可監(jiān)聽到項(xiàng)目啟動(dòng)成功與關(guān)閉時(shí)的事件,相關(guān)接口如下:

  • CommandLineRunner接口:當(dāng)應(yīng)用啟動(dòng)成功后但在開始接受流量之前,會(huì)回調(diào)此接口的實(shí)現(xiàn)類,也可以實(shí)現(xiàn)ApplicationRunner接口,工作的方式與CommandLineRunner與之類似
  • DisposableBean接口:當(dāng)應(yīng)用正要被銷毀前,會(huì)回調(diào)此接口的實(shí)現(xiàn)類,也可以使用@PreDestroy注解,被標(biāo)記的方法也會(huì)被調(diào)用

基于此流程,我們可以創(chuàng)建一個(gè)服務(wù)監(jiān)聽類,用于監(jiān)聽到項(xiàng)目啟動(dòng)成功與關(guān)閉時(shí)的回調(diào)服務(wù),示例代碼如下:

@Component
public?class?AppListener?implements?CommandLineRunner,?DisposableBean?{

????@Override
????public?void?run(String...?args)?throws?Exception?{
????????System.out.println("應(yīng)用啟動(dòng)成功,預(yù)加載相關(guān)數(shù)據(jù)");
????}

????@Override
????public?void?destroy()?throws?Exception?{
????????System.out.println("應(yīng)用正在關(guān)閉,清理相關(guān)數(shù)據(jù)");
????}

}

每一個(gè)SpringApplication在啟用的時(shí)候,都會(huì)向 JVM 注冊(cè)一個(gè)關(guān)閉鉤子shutdown hook,以確保ApplicationContext在退出的時(shí)候,通過這個(gè)勾子通知 JVM,實(shí)現(xiàn)服務(wù)正常的關(guān)閉,以下介紹的所有關(guān)閉服務(wù)的方法,都是基于這一原理進(jìn)行實(shí)現(xiàn)的。

2.1 方法一 通過Actuator的Endpoint機(jī)制關(guān)閉服務(wù)

使用此方法,需要先添加spring-boot-starter-actuator監(jiān)控服務(wù)依賴包,

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

默認(rèn)配置下,shutdown端點(diǎn)是關(guān)閉的,需要在application.properties里配置里面開啟:

management.endpoint.shutdown.enabled=true

雖然Actuator的端點(diǎn),支持通過JMXHTTP進(jìn)行遠(yuǎn)程訪問。而shutdown默認(rèn)配置下是不支持HTTP進(jìn)行Web訪問的,所以使用HTTP請(qǐng)求進(jìn)行關(guān)閉時(shí)的配置,也需要開啟:

management.endpoints.web.exposure.include=shutdown

最后將SpringBoot服務(wù)啟動(dòng)之后,使用POST請(qǐng)求類型,調(diào)用以下接口,即可實(shí)現(xiàn)關(guān)閉服務(wù)!

http://127.0.0.1:8080/actuator/shutdown

2.2 方法二 使用ApplicationContext的close方法關(guān)閉服務(wù)

如果你不想添加spring-boot-starter-actuator監(jiān)控服務(wù)依賴包來關(guān)停服務(wù),也可以使用ApplicationContextclose方法來關(guān)停服務(wù),他會(huì)自動(dòng)銷毀bean對(duì)象并關(guān)停服務(wù)。

只需要在應(yīng)用啟用的時(shí)候,獲取ApplicationContext對(duì)象,然后在相關(guān)的位置調(diào)用close方法,就可以關(guān)閉服務(wù)。

示例代碼如下:

@SpringBootApplication
public?class?Application?{

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

??????try?{
?????????TimeUnit.SECONDS.sleep(10);
??????}?catch?(InterruptedException?e)?{
?????????e.printStackTrace();
??????}
??????//啟動(dòng)10秒以后,自動(dòng)關(guān)閉
??????context.close();
????}
}

當(dāng)然我們也可以自己寫一個(gè)Controller,獲取對(duì)應(yīng)的ApplicationContext對(duì)象,通過api操作調(diào)用close方法關(guān)停服務(wù),示例代碼如下:

@RestController
public?class?ShutdownController?implements?ApplicationContextAware?{

????private?ApplicationContext?context;

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

????/**
?????*?關(guān)閉服務(wù)
?????*/
????@GetMapping("/shutdown")
????public?void?shutdownContext()?{
????????((ConfigurableApplicationContext)?context).close();
????}
}

2.3 方法三 監(jiān)聽服務(wù)pid,通過kill方式關(guān)閉服務(wù)

通過api方式來關(guān)停服務(wù),在很多人看來并不安全,因?yàn)橐坏┙涌谛孤┝耍馕吨脩艨梢噪S便請(qǐng)求這個(gè)接口來關(guān)閉服務(wù),其影響不言而喻,因此很多人建議在服務(wù)端,通過其他的方式來關(guān)閉服務(wù),比如通過進(jìn)程命令方式來關(guān)停。

springboot啟動(dòng)的時(shí)候?qū)?yīng)用進(jìn)程 ID 寫入一個(gè)app.pid文件,生成的路徑可以指定,然后通過腳本命令方式來關(guān)閉服務(wù)。

啟動(dòng)示例代碼如下:

@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();
????}
}

通過如下命令方式,可以安全的關(guān)閉服務(wù)。

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

這種方式,也是目前在linux操作系統(tǒng)中,使用較為普遍的一種解決方案,區(qū)別在于實(shí)現(xiàn)的方式可能不同,有的不用寫文件,通過其他方式來獲取應(yīng)用進(jìn)程 ID。

如果使用kill -9 <pid>的方式關(guān)閉服務(wù),服務(wù)的監(jiān)聽器不會(huì)收到任何消息,類似于直接強(qiáng)殺應(yīng)用進(jìn)程,此方法不可??!

2.4 方法四 使用SpringApplication的exit方法關(guān)閉服務(wù)

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

示例代碼如下:

@SpringBootApplication
public?class?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秒后,關(guān)閉服務(wù)
????????exitApplication(context);
????}

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

}

三、其他監(jiān)聽介紹

3.1、ApplicationListener

如果有些服務(wù),比如定時(shí)任務(wù),我們想在SpringBoot關(guān)閉數(shù)據(jù)源連接池之前,將其關(guān)閉,可以通過實(shí)現(xiàn)ApplicationListener接口,監(jiān)聽bean對(duì)象的變化情況,在bean對(duì)象銷毀之前,執(zhí)行相關(guān)的關(guān)閉任務(wù)。

示例代碼如下:

@Component
public?class?JobTaskListener?implements?ApplicationListener?{

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

3.2、PreDestroy

上文中,我們提到了實(shí)現(xiàn)DisposableBean接口,可以監(jiān)聽?wèi)?yīng)用關(guān)閉前的回調(diào)處理,其實(shí)在自定義的方法上加@PreDestroy注解,也可以實(shí)現(xiàn)相同的效果。

示例代碼如下:

@Component
public?class?AppDestroyConfig?{

????@PreDestroy
????public?void?PreDestroy(){
????????System.out.println("應(yīng)用程序正在關(guān)閉。。。");
????}
}

到此這篇關(guān)于SpringBoot實(shí)現(xiàn)優(yōu)雅停機(jī)的正確方法的文章就介紹到這了,更多相關(guān)SpringBoot優(yōu)雅停機(jī)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 簡單談?wù)凷pringMVC轉(zhuǎn)發(fā)和重定向的區(qū)別

    簡單談?wù)凷pringMVC轉(zhuǎn)發(fā)和重定向的區(qū)別

    下面小編就為大家?guī)硪黄唵握務(wù)凷pringMVC轉(zhuǎn)發(fā)和重定向的區(qū)別。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • Java線程實(shí)現(xiàn)的三種方式詳細(xì)解析

    Java線程實(shí)現(xiàn)的三種方式詳細(xì)解析

    這篇文章主要介紹了Java線程實(shí)現(xiàn)的三種方式詳細(xì)解析,Java多線程實(shí)現(xiàn)方式主要有三種,繼承Thread類、實(shí)現(xiàn)Runnable接口、使用ExecutorService、Callable、Future實(shí)現(xiàn)有返回結(jié)果的多線程,需要的朋友可以參考下
    2023-12-12
  • 在idea里如何調(diào)整maven內(nèi)存

    在idea里如何調(diào)整maven內(nèi)存

    這篇文章主要介紹了在idea里如何調(diào)整maven內(nèi)存問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • Java?Map.values()方法之如何獲取Map集合中的所有鍵值對(duì)象

    Java?Map.values()方法之如何獲取Map集合中的所有鍵值對(duì)象

    這篇文章主要介紹了Java?Map.values()方法之如何獲取Map集合中的所有鍵值對(duì)象問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Kotlin語言編程Regex正則表達(dá)式實(shí)例詳解

    Kotlin語言編程Regex正則表達(dá)式實(shí)例詳解

    這篇文章主要為大家介紹了Kotlin語言編程Regex正則表達(dá)式實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Spring Boot RabbitMQ 延遲消息實(shí)現(xiàn)完整版示例

    Spring Boot RabbitMQ 延遲消息實(shí)現(xiàn)完整版示例

    本篇文章主要介紹了Spring Boot RabbitMQ 延遲消息實(shí)現(xiàn)完整版示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • java對(duì)象類型轉(zhuǎn)換和多態(tài)性(實(shí)例講解)

    java對(duì)象類型轉(zhuǎn)換和多態(tài)性(實(shí)例講解)

    下面小編就為大家?guī)硪黄猨ava對(duì)象類型轉(zhuǎn)換和多態(tài)性(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • Messges Queue消息隊(duì)列詳解

    Messges Queue消息隊(duì)列詳解

    這篇文章主要介紹了Messges Queue消息隊(duì)列詳解,消息隊(duì)列一般簡稱為 MQ,是指利用高效可靠的消息傳遞機(jī)制進(jìn)行與平臺(tái)無關(guān)的數(shù)據(jù)交流,并基于數(shù)據(jù)通信來進(jìn)行分布式系統(tǒng)的集成,是在消息的傳輸過程中保存消息的容器,需要的朋友可以參考下
    2023-07-07
  • jmeter基礎(chǔ)邏輯控制器之if控制器的使用

    jmeter基礎(chǔ)邏輯控制器之if控制器的使用

    在實(shí)際工作中,當(dāng)使用JMeter做性能腳本或者接口腳本時(shí),當(dāng)遇到需要對(duì)不同的條件做不同的操作時(shí),我們可以使用JMeter中if控制器來實(shí)現(xiàn),本文就詳細(xì)的介紹一下如何使用
    2021-11-11
  • 淺談springboot項(xiàng)目中定時(shí)任務(wù)如何優(yōu)雅退出

    淺談springboot項(xiàng)目中定時(shí)任務(wù)如何優(yōu)雅退出

    這篇文章主要介紹了淺談springboot項(xiàng)目中定時(shí)任務(wù)如何優(yōu)雅退出?具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09

最新評(píng)論

黄龙县| 桑日县| 井研县| 清水县| 汉源县| 凤台县| 游戏| 迁安市| 鄯善县| 铅山县| 拜城县| 深州市| 洪洞县| 饶阳县| 高碑店市| 太康县| 宝鸡市| 砚山县| 石阡县| 马龙县| 平江县| 电白县| 宜昌市| 海南省| 黄龙县| 浦县| 子长县| 嫩江县| 镇安县| 疏勒县| 新河县| 九台市| 南康市| 武平县| 龙岩市| 雅江县| 汾阳市| 扎囊县| 墨玉县| 惠来县| 皋兰县|