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
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...