欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot實現優(yōu)雅停機的三種方式

 更新時間:2025年04月09日 08:27:59   作者:風象南  
優(yōu)雅停機(Graceful?Shutdown)是指應用在接收到停止信號后,能夠妥善處理現有請求、釋放資源,然后再退出的過程,本文將詳細介紹SpringBoot中實現優(yōu)雅停機的三種方式,需要的朋友可以參考下

引言

應用的啟停是一個常見操作。然而,突然終止一個正在運行的應用可能導致正在處理的請求失敗、數據不一致等問題。優(yōu)雅停機(Graceful Shutdown)是指應用在接收到停止信號后,能夠妥善處理現有請求、釋放資源,然后再退出的過程。本文將詳細介紹SpringBoot中實現優(yōu)雅停機的三種方式。

什么是優(yōu)雅停機?

優(yōu)雅停機指的是應用程序在收到停止信號后,不是立即終止,而是遵循以下步驟有序退出:

  • 停止接收新的請求
  • 等待正在處理的請求完成
  • 關閉各種資源連接(數據庫連接池、線程池、消息隊列連接等)
  • 完成必要的清理工作
  • 最后退出應用

優(yōu)雅停機的核心價值在于:

  • 提高用戶體驗,避免請求突然中斷
  • 保障數據一致性,防止數據丟失

方式一:SpringBoot內置的優(yōu)雅停機支持

原理與支持版本

從Spring Boot 2.3版本開始,框架原生支持優(yōu)雅停機機制。這是最簡單且官方推薦的實現方式。

當應用接收到停止信號(如SIGTERM)時,內嵌的Web服務器(如Tomcat、Jetty或Undertow)會執(zhí)行以下步驟:

  • 停止接收新的連接請求
  • 設置現有連接的keepalive為false
  • 等待所有活躍請求處理完成或超時
  • 關閉應用上下文和相關資源

配置方法

application.propertiesapplication.yml中添加簡單配置即可啟用:

server:
  shutdown: graceful

spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

這里的timeout-per-shutdown-phase指定了等待活躍請求完成的最大時間,默認為30秒。

實現示例

下面是一個完整的SpringBoot應用示例,啟用了優(yōu)雅停機:

@SpringBootApplication
public class GracefulShutdownApplication {

    private static final Logger logger = LoggerFactory.getLogger(GracefulShutdownApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(GracefulShutdownApplication.class, args);
        logger.info("Application started");
    }
    
    @RestController
    @RequestMapping("/api")
    static class SampleController {
        
        @GetMapping("/quick")
        public String quickRequest() {
            return "Quick response";
        }
        
        @GetMapping("/slow")
        public String slowRequest() throws InterruptedException {
            // 模擬長時間處理的請求
            logger.info("Start processing slow request");
            Thread.sleep(10000); // 10秒
            logger.info("Finished processing slow request");
            return "Slow response completed";
        }
    }
    
    @Bean
    public ApplicationListener<ContextClosedEvent> contextClosedEventListener() {
        return event -> logger.info("Received spring context closed event - shutting down");
    }
}

測試驗證

  • 啟動應用
  • 發(fā)起一個長時間運行的請求:curl http://localhost:8080/api/slow
  • 在處理過程中,向應用發(fā)送SIGTERM信號:kill -15 <進程ID>,如果是IDEA開發(fā)環(huán)境,可以點擊一次停止服務按鈕
  • 觀察日志輸出:應該能看到應用等待長請求處理完成后才關閉

優(yōu)缺點

優(yōu)點:

  • 配置簡單,官方原生支持
  • 無需額外代碼,維護成本低
  • 適用于大多數Web應用場景
  • 與Spring生命周期事件完美集成

缺點:

  • 僅支持Spring Boot 2.3+版本
  • 對于超出HTTP請求的場景(如長時間運行的作業(yè))需要額外處理
  • 靈活性相對較低,無法精細控制停機流程
  • 只能設置統(tǒng)一的超時時間

適用場景

  • Spring Boot 2.3+版本的Web應用
  • 請求處理時間可預期,不會有超長時間運行的請求
  • 微服務架構中的標準服務

方式二:使用Actuator端點實現優(yōu)雅停機

原理與實現

Spring Boot Actuator提供了豐富的運維端點,其中包括shutdown端點,可用于觸發(fā)應用的優(yōu)雅停機。這種方式的獨特之處在于它允許通過HTTP請求觸發(fā)停機過程,適合需要遠程操作的場景。

配置步驟

  • 添加Actuator依賴:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • 啟用并暴露shutdown端點:
management:
  endpoint:
    shutdown:
      enabled: true
  endpoints:
    web:
      exposure:
        include: shutdown
      base-path: /management
  server:
    port: 8081  # 可選:為管理端點設置單獨端口

使用方法

通過HTTP POST請求觸發(fā)停機:

curl -X POST http://localhost:8081/management/shutdown

請求成功后,會返回類似如下響應:

{
  "message": "Shutting down, bye..."
}

安全性考慮

由于shutdown是一個敏感操作,必須考慮安全性:

spring:
  security:
    user:
      name: admin
      password: secure_password
      roles: ACTUATOR

management:
  endpoints:
    web:
      exposure:
        include: shutdown
  endpoint:
    shutdown:
      enabled: true

# 配置端點安全
management.endpoints.web.base-path: /management

使用安全配置后的訪問方式:

curl -X POST http://admin:secure_password@localhost:8080/management/shutdown

完整實現示例

@SpringBootApplication
@EnableWebSecurity
public class ActuatorShutdownApplication {

    private static final Logger logger = LoggerFactory.getLogger(ActuatorShutdownApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(ActuatorShutdownApplication.class, args);
        logger.info("Application started with Actuator shutdown enabled");
    }
    
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeHttpRequests()
            .requestMatchers("/management/**").hasRole("ACTUATOR")
            .anyRequest().permitAll()
            .and()
            .httpBasic();
        
        return http.build();
    }
    
    @RestController
    static class ApiController {
        
        @GetMapping("/api/hello")
        public String hello() {
            return "Hello, world!";
        }
    }
    
    @Bean
    public ApplicationListener<ContextClosedEvent> shutdownListener() {
        return event -> {
            logger.info("Received shutdown signal via Actuator");
            
            // 等待活躍請求完成
            logger.info("Waiting for active requests to complete...");
            try {
                Thread.sleep(5000); // 簡化示例,實際應監(jiān)控活躍請求
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            
            logger.info("All requests completed, shutting down");
        };
    }
}

優(yōu)缺點

優(yōu)點:

  • 可以通過HTTP請求遠程觸發(fā)停機
  • 適合管理工具和運維腳本集成
  • 可以與Spring Security集成實現訪問控制
  • 支持所有Spring Boot版本(包括2.3之前的版本)

缺點:

  • 需要額外配置和依賴
  • 潛在的安全風險,需謹慎保護端點
  • 對于內部復雜資源的關閉需要額外編碼

適用場景

  • 需要通過HTTP請求觸發(fā)停機的場景
  • 使用運維自動化工具管理應用的部署
  • 集群環(huán)境中需要按特定順序停止服務
  • 內部管理系統(tǒng)需要直接控制應用生命周期

方式三:自定義ShutdownHook實現優(yōu)雅停機

原理與實現

JVM提供了ShutdownHook機制,允許在JVM關閉前執(zhí)行自定義邏輯。通過注冊自定義的ShutdownHook,我們可以實現更加精細和靈活的優(yōu)雅停機控制。這種方式的優(yōu)勢在于可以精確控制資源釋放順序,適合有復雜資源管理需求的應用。

基本實現步驟

  • 創(chuàng)建自定義的ShutdownHandler類
  • 注冊JVM ShutdownHook
  • 在Hook中實現自定義的優(yōu)雅停機邏輯

完整實現示例

以下是一個包含詳細注釋的完整示例:

@SpringBootApplication
public class CustomShutdownHookApplication {

    private static final Logger logger = LoggerFactory.getLogger(CustomShutdownHookApplication.class);

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(CustomShutdownHookApplication.class, args);
        
        // 注冊自定義ShutdownHook
        registerShutdownHook(context);
        
        logger.info("Application started with custom shutdown hook");
    }
    
    private static void registerShutdownHook(ConfigurableApplicationContext context) {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            logger.info("Executing custom shutdown hook");
            try {
                // 1. 停止接收新請求(如果是Web應用)
                if (context.containsBean("tomcatServletWebServerFactory")) {
                    TomcatServletWebServerFactory server = context.getBean(TomcatServletWebServerFactory.class);
                    logger.info("Stopping web server to reject new requests");
                    // 注意: 實際應用中需要找到正確方式停止特定Web服務器
                }
                
                // 2. 等待活躍請求處理完成
                logger.info("Waiting for active requests to complete");
                // 這里可以添加自定義等待邏輯,如檢查活躍連接數或線程狀態(tài)
                Thread.sleep(5000); // 簡化示例
                
                // 3. 關閉自定義線程池
                shutdownThreadPools(context);
                
                // 4. 關閉消息隊列連接
                closeMessageQueueConnections(context);
                
                // 5. 關閉數據庫連接池
                closeDataSourceConnections(context);
                
                // 6. 執(zhí)行其他自定義清理邏輯
                performCustomCleanup(context);
                
                // 7. 最后關閉Spring上下文
                logger.info("Closing Spring application context");
                context.close();
                
                logger.info("Graceful shutdown completed");
            } catch (Exception e) {
                logger.error("Error during graceful shutdown", e);
            }
        }, "GracefulShutdownHook"));
    }
    
    private static void shutdownThreadPools(ApplicationContext context) {
        logger.info("Shutting down thread pools");
        
        // 獲取所有ExecutorService類型的Bean
        Map<String, ExecutorService> executors = context.getBeansOfType(ExecutorService.class);
        
        executors.forEach((name, executor) -> {
            logger.info("Shutting down executor: {}", name);
            executor.shutdown();
            try {
                // 等待任務完成
                if (!executor.awaitTermination(15, TimeUnit.SECONDS)) {
                    logger.warn("Executor did not terminate in time, forcing shutdown: {}", name);
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                logger.warn("Interrupted while waiting for executor shutdown: {}", name);
                executor.shutdownNow();
            }
        });
    }
    
    private static void closeMessageQueueConnections(ApplicationContext context) {
        logger.info("Closing message queue connections");
        
        // 示例:關閉RabbitMQ連接
        if (context.containsBean("rabbitConnectionFactory")) {
            try {
                ConnectionFactory rabbitFactory = context.getBean(ConnectionFactory.class);
                // 適當地關閉連接
                logger.info("Closed RabbitMQ connections");
            } catch (Exception e) {
                logger.error("Error closing RabbitMQ connections", e);
            }
        }
        
        // 示例:關閉Kafka連接
        if (context.containsBean("kafkaConsumerFactory")) {
            try {
                // 關閉Kafka連接的代碼
                logger.info("Closed Kafka connections");
            } catch (Exception e) {
                logger.error("Error closing Kafka connections", e);
            }
        }
    }
    
    private static void closeDataSourceConnections(ApplicationContext context) {
        logger.info("Closing datasource connections");
        
        // 獲取所有DataSource類型的Bean
        Map<String, DataSource> dataSources = context.getBeansOfType(DataSource.class);
        
        dataSources.forEach((name, dataSource) -> {
            try {
                // 對于HikariCP連接池
                if (dataSource instanceof HikariDataSource) {
                    ((HikariDataSource) dataSource).close();
                    logger.info("Closed HikariCP datasource: {}", name);
                }
                // 可以添加其他類型連接池的關閉邏輯
                else {
                    // 嘗試通過反射調用close方法
                    Method closeMethod = dataSource.getClass().getMethod("close");
                    closeMethod.invoke(dataSource);
                    logger.info("Closed datasource: {}", name);
                }
            } catch (Exception e) {
                logger.error("Error closing datasource: {}", name, e);
            }
        });
    }
    
    private static void performCustomCleanup(ApplicationContext context) {
        // 這里可以添加應用特有的清理邏輯
        logger.info("Performing custom cleanup tasks");
        
        // 例如:保存應用狀態(tài)
        // 例如:釋放本地資源
        // 例如:發(fā)送關閉通知給其他系統(tǒng)
    }
    
    @Bean
    public ExecutorService applicationTaskExecutor() {
        return Executors.newFixedThreadPool(10);
    }
    
    @RestController
    @RequestMapping("/api")
    static class ApiController {
        
        @Autowired
        private ExecutorService applicationTaskExecutor;
        
        @GetMapping("/task")
        public String submitTask() {
            applicationTaskExecutor.submit(() -> {
                try {
                    logger.info("Task started, will run for 30 seconds");
                    Thread.sleep(30000);
                    logger.info("Task completed");
                } catch (InterruptedException e) {
                    logger.info("Task interrupted");
                    Thread.currentThread().interrupt();
                }
            });
            return "Task submitted";
        }
    }
}

優(yōu)缺點

優(yōu)點:

  • 最大的靈活性和可定制性
  • 可以精確控制資源關閉順序和方式
  • 適用于復雜應用場景和所有Spring Boot版本
  • 可以處理Spring框架無法管理的外部資源

缺點:

  • 實現復雜度高,需要詳細了解應用資源
  • 維護成本較高
  • 容易出現資源關閉順序錯誤導致的問題

適用場景

  • 具有復雜資源管理需求的應用
  • 需要特定順序關閉資源的場景
  • 使用Spring Boot早期版本(不支持內置優(yōu)雅停機)
  • 非Web應用或混合應用架構
  • 使用了Spring框架不直接管理的資源(如Native資源)

方案對比和選擇指南

下面是三種方案的對比表格,幫助您選擇最適合自己場景的實現方式:

特性/方案SpringBoot內置Actuator端點自定義ShutdownHook
實現復雜度
靈活性
可定制性
框架依賴Spring Boot 2.3+任何Spring Boot版本任何Java應用
額外依賴Actuator
觸發(fā)方式系統(tǒng)信號(SIGTERM)HTTP請求系統(tǒng)信號或自定義
安全性考慮高(需要保護端點)
維護成本
適用Web應用最適合適合適合
適用非Web應用部分適合部分適合最適合
  • 選擇SpringBoot內置方案,如果:

    • 使用Spring Boot 2.3+版本
    • 主要是標準Web應用
    • 沒有特殊的資源管理需求
    • 希望最簡單的配置
  • 選擇Actuator端點方案,如果:

    • 需要通過HTTP請求觸發(fā)停機
    • 使用早期Spring Boot版本
    • 集成了運維自動化工具
    • 已經在使用Actuator進行監(jiān)控
  • 選擇自定義ShutdownHook方案,如果:

    • 有復雜的資源管理需求
    • 需要精確控制停機流程
    • 使用了Spring框架不直接管理的資源
    • 混合架構應用(既有Web又有后臺作業(yè))

結論

優(yōu)雅停機是保障應用可靠性和用戶體驗的重要實踐。SpringBoot提供了多種實現方式,從簡單的配置到復雜的自定義實現,可以滿足不同應用場景的需求。

  • 對于簡單應用:SpringBoot內置方案是最佳選擇,配置簡單,足夠滿足大多數Web應用需求
  • 對于需要遠程觸發(fā)的場景:Actuator端點提供了HTTP接口控制,便于集成運維系統(tǒng)
  • 對于復雜應用:自定義ShutdownHook提供了最大的靈活性,可以精確控制資源釋放順序和方式

無論選擇哪種方式,優(yōu)雅停機都應該成為微服務設計的標準實踐。正確實現優(yōu)雅停機,不僅能提升系統(tǒng)穩(wěn)定性,還能改善用戶體驗,減少因應用重啟或降級帶來的業(yè)務中斷。

以上就是SpringBoot實現優(yōu)雅停機的三種方式的詳細內容,更多關于SpringBoot優(yōu)雅停機方式的資料請關注腳本之家其它相關文章!

相關文章

  • java使用GeoTools讀取shp文件并畫圖的操作代碼

    java使用GeoTools讀取shp文件并畫圖的操作代碼

    GeoTools是ArcGis地圖與java對象的橋梁,今天通過本文給大家分享java使用GeoTools讀取shp文件并畫圖,文章通過實例代碼給大家介紹的非常詳細,需要的朋友參考下吧
    2021-07-07
  • Spring IOC基于注解啟動示例詳析

    Spring IOC基于注解啟動示例詳析

    這篇文章主要給大家介紹了Spring IOC基于注解啟動的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-03-03
  • 基于HttpServletResponse 相關常用方法的應用

    基于HttpServletResponse 相關常用方法的應用

    本篇文章小編為大家介紹,基于HttpServletResponse 相關常用方法的應用,需要的朋友參考下
    2013-04-04
  • 深入了解Java核心類庫--String類

    深入了解Java核心類庫--String類

    這篇文章主要為大家詳細介紹了java String類定義與使用的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能給你帶來幫助
    2021-07-07
  • java8新特性之Optional的深入解析

    java8新特性之Optional的深入解析

    這篇文章主要給大家介紹了關于java8新特性之Optional的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-02-02
  • Java內存模型可見性問題相關解析

    Java內存模型可見性問題相關解析

    這篇文章主要介紹了Java內存模型可見性問題相關解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • Spring Boot 實現https ssl免密登錄(X.509 pki登錄)

    Spring Boot 實現https ssl免密登錄(X.509 pki登錄)

    這篇文章主要介紹了Spring Boot 實現https ssl免密登錄(X.509 pki登錄),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • Java concurrency之公平鎖(二)_動力節(jié)點Java學院整理

    Java concurrency之公平鎖(二)_動力節(jié)點Java學院整理

    這篇文章主要為大家詳細介紹了Java concurrency之公平鎖的第二篇內容,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • Netty 輕松實現文件上傳功能

    Netty 輕松實現文件上傳功能

    今天我們來完成一個使用netty進行文件傳輸的任務。在實際項目中,文件傳輸通常采用FTP或者HTTP附件的方式,對Netty 文件上傳功能感興趣的朋友一起看看吧
    2021-07-07
  • Java中RabbitMQ延遲隊列實現詳解

    Java中RabbitMQ延遲隊列實現詳解

    這篇文章主要介紹了Java中RabbitMQ延遲隊列實現詳解,消息過期后,根據routing-key的不同,又會被死信交換機路由到不同的死信隊列中,消費者只需要監(jiān)聽對應的死信隊列進行消費即可,需要的朋友可以參考下
    2023-09-09

最新評論