一文詳解SpringBoot中CommandLineRunner接口
前言
Spring Boot的CommandLineRunner接口是一個函數(shù)式接口,用于在Spring Boot應用程序啟動后執(zhí)行一些初始化操作。它提供了一個run方法,該方法在應用程序啟動后被調用。
使用CommandLineRunner接口,可以在應用程序啟動后執(zhí)行一些必要的初始化操作,例如加載配置文件、初始化數(shù)據庫連接、創(chuàng)建默認數(shù)據等??梢酝ㄟ^實現(xiàn)CommandLineRunner接口,并重寫run方法來定義自己的初始化邏輯。
實例
導入庫
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
</parent>
<groupId>org.example</groupId>
<artifactId>springboot-CommandLineRunner</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Spring Boot banner</name>
<description>Spring Boot and commandLineRunner</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
application.yaml
server:
port: 8080
spring:
profiles:
active: dev
Runner
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class Runner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
log.info("The Runner start to initialize ...");
}
}
SpringBootCommandLineRunnerApplication
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@Slf4j
public class SpringBootCommandLineRunnerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootCommandLineRunnerApplication.class, args);
log.info("The service to end");
}
}
執(zhí)行結果

在上面的示例中,我們創(chuàng)建了一個名為MyCommandLineRunner的類,并實現(xiàn)了CommandLineRunner接口。在run方法中,我們可以編寫需要在應用程序啟動后執(zhí)行的初始化邏輯。
需要注意的是,實現(xiàn)CommandLineRunner接口的類需要被Spring容器掃描到,可以使用@Component注解或其他方式將其注冊為Spring Bean。
先后順序示例
可以通過@Order()來設置Runner的先后順序,在上面例子的基礎上增加
OrderRunner1
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(1)
@Slf4j
public class OrderRunner1 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
log.info("The OrderRunner1 start to initialize ...");
}
}
OrderRunner2
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(2)
@Slf4j
public class OrderRunner2 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
log.info("The OrderRunner2 start to initialize ...");
}
}
執(zhí)行結果

通常用法

加載初始化數(shù)據
可以實現(xiàn)CommandLineRunner接口,在run方法中加載一些初始化數(shù)據到數(shù)據庫等。適合做一些數(shù)據預加載工作。
示例
@Component
public class DataInitializer implements CommandLineRunner {
@Autowired
private UserRepository userRepository;
@Override
public void run(String... args) throws Exception {
// 創(chuàng)建初始用戶
User admin = new User("admin", "123456");
userRepository.save(admin);
User normalUser = new User("user", "123456");
userRepository.save(normalUser);
System.out.println("數(shù)據加載完畢!");
}
}
這里創(chuàng)建了一個 DataInitializer 類,實現(xiàn) CommandLineRunner 接口。在 run() 方法中,我們注入了 UserRepository,然后創(chuàng)建了兩個用戶對象保存到數(shù)據庫中。這個類會在 Spring Boot 應用啟動完成后執(zhí)行,從而實現(xiàn)了數(shù)據預加載的效果。通過 CommandLineRunner,我們可以靈活地在 Spring Boot 啟動時進行一些初始化操作,如預先加載測試數(shù)據、插入管理員賬戶等,很好地增強了應用的功能。
假設我們有一個User模型和用戶Repository,需要在Spring Boot啟動時預加載幾個用戶數(shù)據,可以這樣使用CommandLineRunner:
@Component
public class DataInitializer implements CommandLineRunner {
@Autowired
private UserRepository userRepository;
@Override
public void run(String... args) throws Exception {
// 清除所有數(shù)據
userRepository.deleteAll();
// 創(chuàng)建幾個用戶
User user1 = new User("John", "john@example.com");
User user2 = new User("Mary", "mary@example.com");
userRepository.save(user1);
userRepository.save(user2);
// 打印已保存用戶數(shù)
System.out.println("Number of users saved: " + userRepository.count());
}
}
這里我們實現(xiàn)了CommandLineRunner接口,然后注入UserRepository bean。在run方法中,首先清空所有數(shù)據,然后創(chuàng)建兩個用戶對象并保存,最后打印已保存的用戶數(shù)。這樣在Spring Boot應用啟動完成后,就會自動執(zhí)行run方法,預加載指定的用戶數(shù)據。
啟動后打印應用信息
可以打印出一些應用啟動信息,如啟動端口、運行環(huán)境信息等,用于確認應用配置。
示例
@Component
@Slf4j
public class AppInfoPrinter implements CommandLineRunner {
@Autowired
private Environment environment;
@Override
public void run(String... args) throws Exception {
log.info("========= 打印啟動信息 =========");
// 打印應用端口
log.info(("端口號: " + environment.getProperty("server.port")));
// 打印當前環(huán)境
log.info("當前環(huán)境: " + environment.getProperty("spring.profiles.active"));
// 打印JDK版本
log.info("JDK 版本: " + System.getProperty("java.version"));
log.info("========= 打印啟動信息結束 =========");
}
}
執(zhí)行打印結果

啟動異步任務
可以使用多線程啟動一些異步任務,進行后臺數(shù)據處理等復雜業(yè)務邏輯。
示例
@Component
@Slf4j
public class AsyncTaskRunner implements CommandLineRunner {
@Autowired
private AsyncTaskService asyncTaskService;
@Override
public void run(String... args) throws Exception {
log.info("========= 執(zhí)行任務 =========");
// 在新線程中執(zhí)行任務
new Thread(() -> {
asyncTaskService.doTaskOne();
asyncTaskService.doTaskTwo();
asyncTaskService.doTaskThree();
}).start();
}
}
@Service
@Slf4j
class AsyncTaskService {
public void doTaskOne() {
log.info("執(zhí)行任務1");
}
public void doTaskTwo() {
log.info("執(zhí)行任務2");
}
public void doTaskThree() {
log.info("執(zhí)行任務3");
}
}
執(zhí)行結果
[ main] org.example.runner.AsyncTaskRunner : ========= 執(zhí)行任務 ========= [ Thread-1] org.example.runner.AsyncTaskService : 執(zhí)行任務1 [ Thread-1] org.example.runner.AsyncTaskService : 執(zhí)行任務2 [ Thread-1] org.example.runner.AsyncTaskService : 執(zhí)行任務3
接口健康檢查
可以調用并驗證依賴服務的健康狀態(tài),如果不正??梢越K止Spring Boot啟動。
示例
@Component
@Slf4j
public class HealthCheckRunner implements CommandLineRunner {
@Autowired
private DatabaseService databaseService;
@Autowired
private MessageQueueService messageQueueService;
@Override
public void run(String... args) throws Exception {
if(!databaseService.isConnected()) {
log.error("數(shù)據庫服務不可用,退出應用!");
System.exit(1);
}
if(!messageQueueService.isConnected()) {
log.error("消息隊列服務不可用,退出應用!");
System.exit(1);
}
log.info("所有服務正常,應用啟動。");
}
}
這里我們注入兩個依賴服務 DatabaseService 和 MessageQueueService。在run方法中,調用它們的健康檢查方法,如果任何一個服務不可用,則直接調用System.exit(1)退出Spring Boot應用啟動。
外部服務調用
可以在啟動時調用外部服務,進行驗證、數(shù)據同步等操作。
示例
@Component
public class OtherServiceCheckRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 健康檢查的URL
String healthCheckUrl = "http://localhost:8080/actuator/health";
RestTemplate restTemplate = new RestTemplate();
// 發(fā)送GET請求進行健康檢查
String response = restTemplate.getForObject(healthCheckUrl, String.class);
// 根據響應判斷健康狀態(tài)
if (response.contains("\"status\":\"UP\"")) {
System.out.println("Application is healthy");
} else {
System.out.println("Application is not healthy");
}
}
}
參數(shù)校驗
可以對輸入的運行參數(shù)做校驗,如果不滿足條件可以終止Spring Boot啟動。
示例
@Component
@Slf4j
public class ParameterValidator implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 校驗參數(shù)1
if(args.length < 2) {
log.error("參數(shù)不正確,請傳入至少2個參數(shù)!");
System.exit(1);
}
// 校驗參數(shù)2是否為數(shù)字
if(!args[1].matches("\\d+")) {
log.error("第二個參數(shù)必須是數(shù)字!");
System.exit(1);
}
// 校驗通過,應用繼續(xù)啟動
log.info("參數(shù)校驗通過,應用啟動中...");
}
}
在run方法中,我們可以對main方法輸入的參數(shù)args進行自定義校驗:
檢查參數(shù)數(shù)量校驗參數(shù)類型
如果參數(shù)不滿足需求,可以直接調用System.exit(1)來終止Spring Boot的啟動。這樣就可以在應用啟動前驗證參數(shù)的正確性,避免應用啟動后發(fā)生未知錯誤。
動態(tài)設置配置
可以根據運行參數(shù)等條件動態(tài)設置Spring Boot的配置,實現(xiàn)不同環(huán)境的適配。
示例 application.yaml
myconfig: foo: 十五 bar: 1
MyConfig
@Component
@Data
@ConfigurationProperties(prefix = "myconfig")
public class MyConfig {
private String foo;
private int bar;
// getter和setter方法省略
@Override
public String toString() {
return "MyConfig{" +
"foo='" + foo + '\'' +
", bar=" + bar +
'}';
}
}
ConfigRunner
@Component
@EnableConfigurationProperties(MyConfig.class)
public class ConfigRunner implements CommandLineRunner {
@Autowired
private MyConfig myConfig;
@Override
public void run(String... args) throws Exception {
// 打印當前配置
System.out.println("Current config: " + myConfig);
// 動態(tài)設置配置
myConfig.setFoo("new value");
myConfig.setBar(100);
// 打印更新后的配置
System.out.println("Updated config: " + myConfig);
}
}
啟動阻塞
可以使應用啟動后阻塞住主線程,防止main方法直接退出,從而保持Spring Boot應用運行。
示例
@Component
@Slf4j
public class StartBlocker implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 加載提示信息
log.info("正在等待管理員授權...");
// 等待授權,阻塞啟動流程
waitAuth();
// 授權完成后繼續(xù)啟動
log.info("管理員已授權,應用啟動中...");
}
private void waitAuth() {
// 死循環(huán)模擬等待管理員操作授權
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
}
}
總結
通過 CommandLineRunner,我們可以深度控制 Spring Boot 應用的啟動流程,在應用啟動階段增強各種自定義邏輯。是 Spring Boot 提供的一個很實用的擴展點。
以上就是一文詳解SpringBoot中CommandLineRunner接口的詳細內容,更多關于SpringBoot CommandLineRunner接口的資料請關注腳本之家其它相關文章!
相關文章
SpringBoot多數(shù)據源讀寫分離的自定義配置問題及解決方法
這篇文章主要介紹了SpringBoot多數(shù)據源讀寫分離的自定義配置,我們可以通過自定義配置數(shù)據庫配置類來解決這個問題,方式有很多,不同的業(yè)務采用的方式也不同,下面我簡單的介紹我們項目的使用的方法2022-06-06
解決FeignClient發(fā)送post請求異常的問題
這篇文章主要介紹了FeignClient發(fā)送post請求異常的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
SpringBoot Actuator未授權訪問漏洞解決方案
工作的時候遇到過提示Spring Boot后端存在Actuator未授權訪問漏洞,網上有很多詳細的解釋文章,在這里做一個簡單的總結、介紹和分享,需要的朋友可以參考下2023-09-09
面向對象和面向過程的區(qū)別(動力節(jié)點java學院整理)
很多朋友不清楚面向對象和面向過程有什么區(qū)別,接下來小編給大家整理了關于面向對象和面向過程的區(qū)別講解,感興趣的朋友可以參考下2017-04-04
用SpringBoot+Vue+uniapp小程序實現(xiàn)在線房屋裝修管理系統(tǒng)
這篇文章主要介紹了用SpringBoot+Vue+uniapp實現(xiàn)在線房屋裝修管理系統(tǒng),針對裝修樣板信息管理混亂,出錯率高,信息安全性差,勞動強度大,費時費力等問題開發(fā)了這套系統(tǒng),需要的朋友可以參考下2023-03-03
關于springboot中對sqlSessionFactoryBean的自定義
這篇文章主要介紹了springboot中對sqlSessionFactoryBean的自定義方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12

