Spring Boot 中的 ApplicationRunner 和 CommandLineRunner

来源:https://www.cnblogs.com/god23bin/archive/2023/03/28/spring_boot_application_runner_and_command_line_runner.html
-Advertisement-
Play Games

Spring Boot 應用,在啟動的時候,如果想做一些事情,比如預先載入並緩存某些數據,讀取某些配置等等。總而言之,做一些初始化的操作時,那麼 Spring Boot 就提供了兩個介面幫助我們實現。 ...


前言

一般項目中的初始化操作,初次遇見,妙不可言。如果你還有哪些方式可用於初始化操作,歡迎在評論中分享出來~

ApplicationRunner 和 CommandLineRunner

Spring Boot 應用,在啟動的時候,如果想做一些事情,比如預先載入並緩存某些數據,讀取某些配置等等。總而言之,做一些初始化的操作時,那麼 Spring Boot 就提供了兩個介面幫助我們實現。

這兩個介面是:

  • ApplicationRunner 介面
  • CommandLineRunner 介面

源碼如下:

ApplicationRunner

package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link ApplicationRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 *
 * @author Phillip Webb
 * @since 1.3.0
 * @see CommandLineRunner
 */
@FunctionalInterface
public interface ApplicationRunner {

   /**
    * Callback used to run the bean.
    * @param args incoming application arguments
    * @throws Exception on error
    */
   void run(ApplicationArguments args) throws Exception;

}

CommandLineRunner

package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 * <p>
 * If you need access to {@link ApplicationArguments} instead of the raw String array
 * consider using {@link ApplicationRunner}.
 *
 * @author Dave Syer
 * @since 1.0.0
 * @see ApplicationRunner
 */
@FunctionalInterface
public interface CommandLineRunner {

   /**
    * Callback used to run the bean.
    * @param args incoming main method arguments
    * @throws Exception on error
    */
   void run(String... args) throws Exception;

}

可以看到,這兩個介面的註釋幾乎一模一樣,如出一轍。大致的意思就是,這兩個介面可以在 Spring 的環境下指定一個 Bean 運行(run)某些你想要做的事情,如果你有多個 Bean 進行指定,那麼可以通過 Ordered 介面或者 @Order 註解指定執行順序。

說白了,就是可以搞多個實現類實現這兩個介面,通過 @Order 確定實現類的誰先運行,誰後運行

@Order

再看看 @Order 註解的源碼:

/**
 * {@code @Order} defines the sort order for an annotated component.
 *
 * <p>The {@link #value} is optional and represents an order value as defined in the
 * {@link Ordered} interface. Lower values have higher priority. The default value is
 * {@code Ordered.LOWEST_PRECEDENCE}, indicating lowest priority (losing to any other
 * specified order value).
 * ..... 省略剩下的註釋
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {

	/**
	 * The order value.
	 * <p>Default is {@link Ordered#LOWEST_PRECEDENCE}.
	 * @see Ordered#getOrder()
	 */
	int value() default Ordered.LOWEST_PRECEDENCE;

}

Ordered.LOWEST_PRECEDENCE 的預設值是 Integer.MAX_VALUE

在頂部的註釋中,可以知道,@Order 註解是給使用了 @Component 註解的 Bean 定義排序順序(defines the sort order for an annotated component),然後 @Order 註解的 value 屬性值越低,那麼代表這個 Bean 有著更高的優先順序(Lower values have higher priority)。

測試

分別寫兩個實現類,實現這兩個介面,然後啟動 Spring Boot 項目,看看執行順序

ApplicationRunnerImpl:

@Slf4j
@Component
public class ApplicationRunnerImpl implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("我正在載入 ------------------> ApplicationRunnerImpl");
    }
}

CommandLineRunnerImpl:

@Slf4j
@Component
public class CommandLineRunnerImpl implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        log.info("我正在載入 ------------------> CommandLineRunnerImpl");
    }
}

控制台輸出:

2023-03-26 15:46:38.344  INFO 25616 --- [           main] c.g.demo.init.ApplicationRunnerImpl      : 我正在載入 ------------------> ApplicationRunnerImpl
2023-03-26 15:46:38.344  INFO 25616 --- [           main] c.g.demo.init.CommandLineRunnerImpl      : 我正在載入 ------------------> CommandLineRunnerImpl

可以看到,是 ApplicationRunnerImpl 先運行的,CommandLineRunnerImpl 後運行的。

我們給 CommandLineRunnerImpl 加上 @Order 註解,給其 value 屬性設置 10:

@Slf4j
@Order(10)
@Component
public class CommandLineRunnerImpl implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        log.info("我正在載入 ------------------> CommandLineRunnerImpl");
    }
}

控制台輸出:

2023-03-26 15:50:43.524  INFO 16160 --- [           main] c.g.demo.init.CommandLineRunnerImpl      : 我正在載入 ------------------> CommandLineRunnerImpl
2023-03-26 15:50:43.524  INFO 16160 --- [           main] c.g.demo.init.ApplicationRunnerImpl      : 我正在載入 ------------------> ApplicationRunnerImpl

區別

回到這兩個介面,看似一模一樣,但肯定有小小區別的,最主要的區別就是介面的抽象方法的參數

ApplicationRunner:

  • void run(ApplicationArguments args) throws Exception;

CommandLineRunner:

  • void run(String... args) throws Exception;

具體來說,ApplicationRunner 介面的 run 方法中的參數為 ApplicationArguments 對象,該對象封裝了應用程式啟動時傳遞的命令行參數和選項。

CommandLineRunner 介面的 run 方法中的參數為 String 數組,該數組直接包含了應用程式啟動時傳遞的命令行參數和選項。

測試

列印下命令行參數:

@Slf4j
@Component
public class ApplicationRunnerImpl implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner: optionNames = " + args.getOptionNames() + ", sourceArgs = " + args.getSourceArgs());
    }
}
@Slf4j
@Component
public class CommandLineRunnerImpl implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner: " + Arrays.toString(args));
    }
}

用 Maven 打包項目為 Jar 包,啟動該 Jar 包:

// 使用 java -jar 啟動,加上兩個參數:name 和 description
java -jar demo-0.0.1-SNAPSHOT.jar --name=god23bin --description=like_me

輸出:

ApplicationRunner: optionNames = [name, description]sourceArgs = [Ljava.lang.String;@5c90e579
CommandLineRunner: [--name=god23bin, --description=like_me]

最後的最後

由本人水平所限,難免有錯誤以及不足之處, 屏幕前的靚仔靚女們 如有發現,懇請指出!

最後,謝謝你看到這裡,謝謝你認真對待我的努力,希望這篇博客對你有所幫助!

你輕輕地點了個贊,那將在我的心裡世界增添一顆明亮而耀眼的星!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • XSS攻擊是什麼? XSS攻擊是指攻擊者利用網站中的漏洞,向頁面中註入惡意腳本,從而獲取用戶的信息或者控制用戶的電腦。 舉一個通俗的例子,早期使用JSP頁面渲染頁面的項目,如果將用戶名改成nick<alert>1</alert>,則當用戶打開頁面時,就會彈出一個警告框,而這個警告框可以被惡意腳本所 ...
  • 一站式的消息管理器 在網路應用中,消息處理是必不可少的,該文章主要簡單介紹一款簡單的消息管理器的實現,其具備以下功能: 提供多種消息序列化和反序列化方式,目前支持JDK、ProtoStuff以及JSON,提供其他自定義的序列化/反序列化器插口。 提供多種消息加密/解密,目前支持對稱加密:AES、不對 ...
  • 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。本篇介紹 VLD 配置文件中配置項 SelfTest 的使用方法。 ...
  • 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。本篇介紹 VLD 配置文件中配置項 ReportTo 的使用方法。 ...
  • 層級關係、層級控制: 調整Z軸順序 點擊查看代碼 label1 = QLabel(window) label1.setText("標簽1") label1.resize(200, 200) label1.setStyleSheet("background-color: red;") label2 = ...
  • 某大廠面試題1 1. 分散式事務的一致性問題 事務的四大特性(ACID) 原子性(Atomicity):一個事務(transaction)要麼沒有開始,要麼全部完成,不存在中間狀態。 一致性(Consistency):事務的執行不會破壞數據的正確性,即符合約束。 隔離性(Isolation):多個事 ...
  • 問題1 問題原因:在數據源配置類中沒有創建事務管理 在數據源配置類中添加好事務管理器的Bean即可 問題2 其實出現這個問題實質就是mapper介面和mapper.xml文件沒有映射起來。 常見的錯誤如下: 1.mapper.xml中的namespace和實際的mapper文件不一致 這個問題其實很 ...
  • order by是怎麼工作的? 在你開發應用的時候,一定會經常碰到需要根據指定的欄位排序來顯示結果的需求。還是以我們前面舉例用過的市民表為例,假設你要查詢城市是“杭州”的所有人名字,並且按照姓名排序返回前 1000 個人的姓名、年齡。 假設這個表的部分定義是這樣的: CREATE TABLE `t` ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...