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

SpringBoot CommandLineRunner應用啟動后執(zhí)行代碼實例

 更新時間:2025年04月15日 09:14:41   作者:程序媛學姐  
本文將深入探討CommandLineRunner的工作原理、使用場景及最佳實踐,幫助開發(fā)者充分利用這一功能,構建更加健壯的Spring Boot應用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

引言

在企業(yè)級應用開發(fā)中,我們經常需要在應用啟動完成后執(zhí)行一些初始化操作,例如預加載緩存數(shù)據(jù)、創(chuàng)建默認管理員賬戶、數(shù)據(jù)遷移等任務。

Spring Boot提供了CommandLineRunner接口,使開發(fā)者能夠優(yōu)雅地實現(xiàn)這些需求。

一、CommandLineRunner基礎

CommandLineRunner是Spring Boot提供的一個接口,用于在Spring應用上下文完全初始化后、應用正式提供服務前執(zhí)行特定的代碼邏輯。該接口只包含一個run方法,方法參數(shù)為應用啟動時傳入的命令行參數(shù)。

CommandLineRunner接口定義如下:

@FunctionalInterface
public interface CommandLineRunner {
    /**
     * 在SpringApplication啟動后回調
     * @param args 來自應用程序的命令行參數(shù)
     * @throws Exception 如果發(fā)生錯誤
     */
    void run(String... args) throws Exception;
}

當一個Spring Boot應用啟動時,Spring容器會在完成所有Bean的初始化后,自動檢索并執(zhí)行所有實現(xiàn)了CommandLineRunner接口的Bean。

這種機制為應用提供了一個明確的初始化時機,確保所有依賴項都已準備就緒。

二、基本用法

2.1 創(chuàng)建CommandLineRunner實現(xiàn)

實現(xiàn)CommandLineRunner接口的最簡單方式是創(chuàng)建一個組件類并實現(xiàn)該接口:

package com.example.demo.runner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

/**
 * 簡單的CommandLineRunner實現(xiàn)
 * 用于演示基本用法
 */
@Component
public class SimpleCommandLineRunner implements CommandLineRunner {

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

    @Override
    public void run(String... args) throws Exception {
        logger.info("應用啟動完成,開始執(zhí)行初始化操作...");
        
        // 執(zhí)行初始化邏輯
        logger.info("初始化操作完成");
        
        // 如果需要,可以訪問命令行參數(shù)
        if (args.length > 0) {
            logger.info("接收到的命令行參數(shù):");
            for (int i = 0; i < args.length; i++) {
                logger.info("參數(shù) {}: {}", i, args[i]);
            }
        }
    }
}

通過@Component注解,Spring會自動掃描并注冊這個Bean,然后在應用啟動完成后調用其run方法。

2.2 使用Lambda表達式

由于CommandLineRunner是一個函數(shù)式接口,我們也可以使用Lambda表達式簡化代碼。這種方式適合實現(xiàn)簡單的初始化邏輯:

package com.example.demo.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 通過@Bean方法創(chuàng)建CommandLineRunner
 */
@Configuration
public class AppConfig {

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

    @Bean
    public CommandLineRunner initDatabase() {
        return args -> {
            logger.info("初始化數(shù)據(jù)庫連接池...");
            // 執(zhí)行數(shù)據(jù)庫初始化邏輯
        };
    }
    
    @Bean
    public CommandLineRunner loadCache() {
        return args -> {
            logger.info("預加載緩存數(shù)據(jù)...");
            // 執(zhí)行緩存預熱邏輯
        };
    }
}

在這個例子中,我們通過@Bean方法創(chuàng)建了兩個CommandLineRunner實例,分別負責數(shù)據(jù)庫初始化和緩存預熱。

三、進階特性

3.1 執(zhí)行順序控制

當應用中存在多個CommandLineRunner時,可能需要控制它們的執(zhí)行順序。

Spring提供了@Order注解(或實現(xiàn)Ordered接口)來實現(xiàn)這一需求:

package com.example.demo.runner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 具有執(zhí)行順序的CommandLineRunner
 * Order值越小,優(yōu)先級越高,執(zhí)行越早
 */
@Component
@Order(1) // 優(yōu)先級高,最先執(zhí)行
public class DatabaseInitializer implements CommandLineRunner {

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

    @Override
    public void run(String... args) throws Exception {
        logger.info("第一步:初始化數(shù)據(jù)庫...");
        // 數(shù)據(jù)庫初始化邏輯
    }
}

@Component
@Order(2) // 次優(yōu)先級
public class CacheWarmer implements CommandLineRunner {

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

    @Override
    public void run(String... args) throws Exception {
        logger.info("第二步:預熱緩存...");
        // 緩存預熱邏輯
    }
}

@Component
@Order(3) // 最后執(zhí)行
public class NotificationInitializer implements CommandLineRunner {

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

    @Override
    public void run(String... args) throws Exception {
        logger.info("第三步:初始化通知服務...");
        // 通知服務初始化邏輯
    }
}

通過@Order注解,我們可以精確控制各個初始化任務的執(zhí)行順序,確保依賴關系得到滿足。值得注意的是,Order值越小,優(yōu)先級越高,執(zhí)行越早。

3.2 依賴注入

CommandLineRunner作為Spring管理的Bean,可以充分利用依賴注入機制:

package com.example.demo.runner;

import com.example.demo.service.UserService;
import com.example.demo.service.SystemConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

/**
 * 演示在CommandLineRunner中使用依賴注入
 */
@Component
public class SystemInitializer implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(SystemInitializer.class);
    
    private final UserService userService;
    private final SystemConfigService configService;
    
    @Autowired
    public SystemInitializer(UserService userService, SystemConfigService configService) {
        this.userService = userService;
        this.configService = configService;
    }

    @Override
    public void run(String... args) throws Exception {
        logger.info("系統(tǒng)初始化開始...");
        
        // 創(chuàng)建默認管理員賬戶
        if (!userService.adminExists()) {
            logger.info("創(chuàng)建默認管理員賬戶");
            userService.createDefaultAdmin();
        }
        
        // 加載系統(tǒng)配置
        logger.info("加載系統(tǒng)配置到內存");
        configService.loadAllConfigurations();
        
        logger.info("系統(tǒng)初始化完成");
    }
}

這個例子展示了如何在CommandLineRunner中注入并使用服務組件,實現(xiàn)更復雜的初始化邏輯。

3.3 異常處理

CommandLineRunner的run方法允許拋出異常。如果在執(zhí)行過程中拋出異常,Spring Boot應用將無法正常啟動。

這一特性可以用來確保關鍵的初始化操作必須成功完成:

package com.example.demo.runner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

/**
 * 演示CommandLineRunner中的異常處理
 */
@Component
public class CriticalInitializer implements CommandLineRunner {

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

    @Override
    public void run(String... args) throws Exception {
        logger.info("執(zhí)行關鍵初始化操作...");
        
        try {
            // 執(zhí)行可能失敗的操作
            boolean success = performCriticalOperation();
            
            if (!success) {
                // 如果操作未能成功完成,阻止應用啟動
                throw new RuntimeException("關鍵初始化操作失敗,應用無法啟動");
            }
            
            logger.info("關鍵初始化操作完成");
        } catch (Exception e) {
            logger.error("初始化過程中發(fā)生錯誤: {}", e.getMessage());
            // 重新拋出異常,阻止應用啟動
            throw e;
        }
    }
    
    private boolean performCriticalOperation() {
        // 模擬關鍵操作的執(zhí)行
        return true; // 返回操作結果
    }
}

在這個例子中,如果關鍵初始化操作失敗,應用將無法啟動,從而避免系統(tǒng)在不完整狀態(tài)下運行。

四、實際應用場景

CommandLineRunner適用于多種實際場景,下面是一些常見的應用:

4.1 數(shù)據(jù)遷移

在系統(tǒng)升級或數(shù)據(jù)結構變更時,可以使用CommandLineRunner執(zhí)行數(shù)據(jù)遷移操作:

@Component
@Order(1)
public class DataMigrationRunner implements CommandLineRunner {

    private final DataMigrationService migrationService;
    private static final Logger logger = LoggerFactory.getLogger(DataMigrationRunner.class);
    
    @Autowired
    public DataMigrationRunner(DataMigrationService migrationService) {
        this.migrationService = migrationService;
    }

    @Override
    public void run(String... args) throws Exception {
        logger.info("檢查數(shù)據(jù)庫版本并執(zhí)行遷移...");
        
        // 獲取當前數(shù)據(jù)庫版本
        String currentVersion = migrationService.getCurrentVersion();
        logger.info("當前數(shù)據(jù)庫版本: {}", currentVersion);
        
        // 執(zhí)行遷移
        boolean migrationNeeded = migrationService.checkMigrationNeeded();
        if (migrationNeeded) {
            logger.info("需要執(zhí)行數(shù)據(jù)遷移");
            migrationService.performMigration();
            logger.info("數(shù)據(jù)遷移完成");
        } else {
            logger.info("無需數(shù)據(jù)遷移");
        }
    }
}

4.2 任務調度初始化

對于使用動態(tài)任務調度的應用,可以在啟動時從數(shù)據(jù)庫加載調度配置:

@Component
public class SchedulerInitializer implements CommandLineRunner {

    private final TaskSchedulerService schedulerService;
    private final TaskDefinitionRepository taskRepository;
    private static final Logger logger = LoggerFactory.getLogger(SchedulerInitializer.class);
    
    @Autowired
    public SchedulerInitializer(TaskSchedulerService schedulerService, 
                               TaskDefinitionRepository taskRepository) {
        this.schedulerService = schedulerService;
        this.taskRepository = taskRepository;
    }

    @Override
    public void run(String... args) throws Exception {
        logger.info("初始化任務調度器...");
        
        // 從數(shù)據(jù)庫加載任務定義
        List<TaskDefinition> tasks = taskRepository.findAllActiveTasks();
        logger.info("加載了{}個調度任務", tasks.size());
        
        // 注冊任務到調度器
        for (TaskDefinition task : tasks) {
            schedulerService.scheduleTask(task);
            logger.info("注冊任務: {}, cron: {}", task.getName(), task.getCronExpression());
        }
        
        logger.info("任務調度器初始化完成");
    }
}

4.3 外部系統(tǒng)連接測試

在應用啟動時,可以測試與關鍵外部系統(tǒng)的連接狀態(tài):

@Component
public class ExternalSystemConnectionTester implements CommandLineRunner {

    private final List<ExternalSystemConnector> connectors;
    private static final Logger logger = LoggerFactory.getLogger(ExternalSystemConnectionTester.class);
    
    @Autowired
    public ExternalSystemConnectionTester(List<ExternalSystemConnector> connectors) {
        this.connectors = connectors;
    }

    @Override
    public void run(String... args) throws Exception {
        logger.info("測試外部系統(tǒng)連接...");
        
        for (ExternalSystemConnector connector : connectors) {
            String systemName = connector.getSystemName();
            logger.info("測試連接到: {}", systemName);
            
            try {
                boolean connected = connector.testConnection();
                if (connected) {
                    logger.info("{} 連接成功", systemName);
                } else {
                    logger.warn("{} 連接失敗,但不阻止應用啟動", systemName);
                }
            } catch (Exception e) {
                logger.error("{} 連接異常: {}", systemName, e.getMessage());
                // 根據(jù)系統(tǒng)重要性決定是否拋出異常阻止應用啟動
            }
        }
        
        logger.info("外部系統(tǒng)連接測試完成");
    }
}

五、最佳實踐

在使用CommandLineRunner時,以下最佳實踐可以幫助開發(fā)者更有效地利用這一功能:

  • 職責單一:每個CommandLineRunner應專注于一個特定的初始化任務,遵循單一職責原則。
  • 合理分組:相關的初始化任務可以組織在同一個CommandLineRunner中,減少代碼碎片化。
  • 異步執(zhí)行:對于耗時的初始化任務,考慮使用異步執(zhí)行,避免延長應用啟動時間:
@Component
public class AsyncInitializer implements CommandLineRunner {

    private final TaskExecutor taskExecutor;
    private static final Logger logger = LoggerFactory.getLogger(AsyncInitializer.class);
    
    @Autowired
    public AsyncInitializer(TaskExecutor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    @Override
    public void run(String... args) throws Exception {
        logger.info("啟動異步初始化任務...");
        
        taskExecutor.execute(() -> {
            try {
                logger.info("異步任務開始執(zhí)行");
                Thread.sleep(5000); // 模擬耗時操作
                logger.info("異步任務執(zhí)行完成");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                logger.error("異步任務被中斷", e);
            } catch (Exception e) {
                logger.error("異步任務執(zhí)行失敗", e);
            }
        });
        
        logger.info("異步初始化任務已提交,應用繼續(xù)啟動");
    }
}
  • 優(yōu)雅降級:對于非關鍵性初始化任務,實現(xiàn)優(yōu)雅降級,避免因次要功能故障而阻止整個應用啟動。
  • 合理日志:使用適當?shù)娜罩炯墑e記錄初始化過程,便于問題排查和性能分析。
  • 條件執(zhí)行:根據(jù)環(huán)境或配置條件決定是否執(zhí)行特定的初始化任務,增強靈活性:
@Component
@ConditionalOnProperty(name = "app.cache.preload", havingValue = "true")
public class ConditionalInitializer implements CommandLineRunner {

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

    @Override
    public void run(String... args) throws Exception {
        logger.info("執(zhí)行條件初始化任務,僅在配置啟用時執(zhí)行");
        // 僅在特定條件下執(zhí)行的初始化邏輯
    }
}

總結

Spring Boot的CommandLineRunner接口為應用提供了一種優(yōu)雅的機制,用于在啟動完成后執(zhí)行初始化代碼。

通過實現(xiàn)這一接口,開發(fā)者可以確保在應用對外提供服務前,必要的準備工作已經完成。

結合@Order注解可以精確控制多個初始化任務的執(zhí)行順序,依賴注入機制使得各種服務組件可以在初始化過程中方便地使用。

在實際應用中,CommandLineRunner可以用于數(shù)據(jù)遷移、緩存預熱、連接測試等多種場景。

通過遵循單一職責原則、合理組織代碼、實現(xiàn)異步執(zhí)行和優(yōu)雅降級等最佳實踐,可以構建更加健壯和高效的Spring Boot應用。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • SpringBoot整合Canal與RabbitMQ監(jiān)聽數(shù)據(jù)變更記錄

    SpringBoot整合Canal與RabbitMQ監(jiān)聽數(shù)據(jù)變更記錄

    這篇文章主要介紹了SpringBoot整合Canal與RabbitMQ監(jiān)聽數(shù)據(jù)變更記錄,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • java字符串切割實例學習(獲取文件名)

    java字符串切割實例學習(獲取文件名)

    在Java中處理一些路徑相關的問題的時候,如要取出ie瀏覽器上傳文件的文件名,由于ie會把整個文件路徑都作為文件名上傳,需要用java.lang.String中的replaceAll或者split來處理,下面看看使用方法
    2013-12-12
  • Java實現(xiàn)文件上傳和url格式校驗工具

    Java實現(xiàn)文件上傳和url格式校驗工具

    這篇文章主要介紹了如何使用Java實現(xiàn)文件上傳和url格式校驗工具,主要用于文件類型校驗,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2026-04-04
  • 一文詳解Java如何防止DDoS攻擊

    一文詳解Java如何防止DDoS攻擊

    DDoS(分布式拒絕服務)攻擊是一種常見的網(wǎng)絡攻擊手段在?Java?應用開發(fā)中,了解?DDoS?攻擊的原理和防御策略至關重要,下面小編來和大家詳細講講
    2025-05-05
  • Spring Security添加二次認證的項目實踐

    Spring Security添加二次認證的項目實踐

    在用戶自動登錄后,可以通過對密碼進行二次校驗進而確保用戶的真實性,本文就來介紹一下Spring Security添加二次認證的項目實踐,具有一定的參考價值,感興趣的可以了解一下
    2023-12-12
  • Spring事物基礎知識及AOP相關陷阱分析

    Spring事物基礎知識及AOP相關陷阱分析

    這篇文章主要介紹了Spring事物基礎知識及AOP相關陷阱,在平時的實際開發(fā)中經常會遇到,只有深入了解了其中的原理,才會在工作中能夠有效應對
    2021-09-09
  • HTTP?與?SpringBoot?參數(shù)提交與接收協(xié)議方式

    HTTP?與?SpringBoot?參數(shù)提交與接收協(xié)議方式

    HTTP參數(shù)提交方式包括URL查詢、表單、JSON/XML、路徑變量、頭部、Cookie、GraphQL、WebSocket和SSE,依據(jù)請求方法和Content-Type差異,SpringBoot通過特定注解如@RequestParam、@RequestBody實現(xiàn)數(shù)據(jù)獲取,本文介紹HTTP與SpringBoot參數(shù)提交與接收協(xié)議方式,感興趣的一起看看
    2025-07-07
  • 基于Java實現(xiàn)Json文件轉換為Excel文件

    基于Java實現(xiàn)Json文件轉換為Excel文件

    這篇文章主要為大家詳細介紹了如何利用Java實現(xiàn)Json文件轉換為Excel文件,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的可以參考一下
    2022-12-12
  • java 一個截取字符串的函數(shù)

    java 一個截取字符串的函數(shù)

    java 編寫一個截取字符串的函數(shù),輸入為一個字符串和字節(jié)數(shù),輸出為按字節(jié)截取的字符串。 要求不能出現(xiàn)截半的情況
    2017-02-02
  • springboot自動裝配的源碼與流程圖

    springboot自動裝配的源碼與流程圖

    在日常的開發(fā)過程中Spring Boot自動裝配的特性給我們開發(fā)減少了很多重復性的工作,這篇文章主要給大家介紹了關于springboot自動裝配的相關資料,需要的朋友可以參考下
    2021-08-08

最新評論

辉南县| 图木舒克市| 南召县| 龙门县| 宣威市| 红原县| 安图县| 贵溪市| 五常市| 积石山| 乳山市| 津市市| 邻水| 增城市| 禄丰县| 旺苍县| 建阳市| 桦川县| 区。| 司法| 文化| 沈阳市| 斗六市| 运城市| 景宁| 敦煌市| 东乡| 新疆| 息烽县| 台安县| 开江县| 行唐县| 平度市| 澄江县| 大庆市| 若羌县| 建水县| 辛集市| 寻乌县| 枣阳市| 浮山县|