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

SpringBoot 中 CommandLineRunner的作用示例詳解

 更新時間:2025年06月10日 11:54:21   作者:程序員小假  
SpringBoot提供的一種簡單的實現(xiàn)方案就是添加一個model并實現(xiàn)CommandLineRunner接口,實現(xiàn)功能的代碼放在實現(xiàn)的run方法中,本文給大家介紹SpringBoot中CommandLineRunner的作用,感興趣的朋友一起看看吧

1、CommandLineRunner

SpringBoot中CommandLineRunner的作用

平常開發(fā)中有可能需要實現(xiàn)在項目啟動后執(zhí)行的功能,SpringBoot提供的一種簡單的實現(xiàn)方案就是添加一個model并實現(xiàn)CommandLineRunner接口,實現(xiàn)功能的代碼放在實現(xiàn)的run方法中。也就是項目一啟動之后,就立即需要執(zhí)行的動作。只需要在項目里面簡單的配置,就可以實現(xiàn)這個功能。 

簡單例子

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyStartupRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("項目已經(jīng)啟動");
    }
}

多個類實現(xiàn)CommandLineRunner接口執(zhí)行順序的保證

通過實現(xiàn)Ordered接口實現(xiàn)控制執(zhí)行順序

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
/**
 * 優(yōu)先級最高
 * 該類期望在springboot 啟動后第一順位執(zhí)行
 * @since 12:57
 **/
@Slf4j
@Component
public class HighOrderCommandLineRunner implements CommandLineRunner, Ordered {
    @Override
    public void run(String... args) throws Exception {
        for (String arg : args) {
            log.info("arg = " + arg);
        }
        log.info("i am highOrderRunner");
    }
    @Override
    public int getOrder() {
        return Integer.MIN_VALUE+1;
    }
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
/**
 * 優(yōu)先級低于{@code HighOrderCommandLineRunner}
 * @since 12:59
 **/
@Slf4j
@Component
public class LowOrderCommandLineRunner implements CommandLineRunner, Ordered {
    @Override
    public void run(String... args) throws Exception {
        log.info("i am lowOrderRunner");
    }
    @Override
    public int getOrder() {
        return Integer.MIN_VALUE+1;
    }
}

啟動Spring Boot程序后,控制臺按照預(yù)定的順序打印出了結(jié)果:

2020-05-30 23:11:03.685  INFO 11976 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-30 23:11:03.701  INFO 11976 --- [           main] c.f.Application  : Started SpringBootApplication in 4.272 seconds (JVM running for 6.316)
2020-05-30 23:11:03.706  INFO 11976 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner
2020-05-30 23:11:03.706  INFO 11976 --- [           main] c.f.LowOrderCommandLineRunner   : i am lowOrderRunner

通過@Order注解實現(xiàn)控制執(zhí)行順序

SpringBoot在項目啟動后會遍歷所有實現(xiàn)CommandLineRunner的實體類并執(zhí)行run方法,如果需要按照一定的順序去執(zhí)行,那么就需要在實體類上使用一個@Order注解(或者實現(xiàn)Order接口)來表明順序

import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(value=2)
public class MyStartupRunner1 implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("執(zhí)行2");
    }
}
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(value=1)
public class MyStartupRunner2 implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("執(zhí)行1");
    }
}

控制臺顯示

執(zhí)行1
執(zhí)行2

根據(jù)控制臺結(jié)果可判斷,@Order 注解的執(zhí)行優(yōu)先級是按value值從小到大順序。

@Order 作用

項目啟動之后,要執(zhí)行的動作是比較的多,那么到底先執(zhí)行哪個,那么就可以利用這個注解限定優(yōu)先級。 :::danger Ordered接口并不能被 @Order注解所代替。

2、ApplicationRunner

在Spring Boot 1.3.0又引入了一個和CommandLineRunner功能一樣的接口ApplicationRunner。CommandLineRunner接收可變參數(shù)String... args,而ApplicationRunner 接收一個封裝好的對象參數(shù)ApplicationArguments。除此之外它們功能完全一樣,甚至連方法名都一樣。聲明一個ApplicationRunner并讓它優(yōu)先級最低:

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
 * 優(yōu)先級最低
 **/
@Slf4j
@Component
public class DefaultApplicationRunner implements ApplicationRunner, Ordered {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("i am applicationRunner");
        Set<String> optionNames = args.getOptionNames();
        log.info("optionNames = " + optionNames);
        String[] sourceArgs = args.getSourceArgs();
        log.info("sourceArgs = " + Arrays.toString(sourceArgs));
        List<String> nonOptionArgs = args.getNonOptionArgs();
        log.info("nonOptionArgs = " + nonOptionArgs);
        List<String> optionValues = args.getOptionValues("foo");
        log.info("optionValues = " + optionValues);
    }
    @Override
    public int getOrder() {
        return Integer.MIN_VALUE+2;
    }
}

按照順序打印了三個類的執(zhí)行結(jié)果:

2020-06-01 13:02:39.420  INFO 19032 --- [           main] c.f.MybatisResultmapApplication  : Started MybatisResultmapApplication in 1.801 seconds (JVM running for 2.266)
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.LowOrderCommandLineRunner    : i am lowOrderRunner
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : i am applicationRunner
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : optionNames = []
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : sourceArgs = []
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : nonOptionArgs = []
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : optionValues = null

 optionValues = null

Ordered接口并不能被 @Order注解所代替。

3、傳遞參數(shù)

Spring Boot應(yīng)用啟動時是可以接受參數(shù)的,換句話說也就是Spring Bootmain方法是可以接受參數(shù)的。這些參數(shù)通過命令行 java -jar yourapp.jar 來傳遞。CommandLineRunner會原封不動照單全收這些接口,這些參數(shù)也可以封裝到ApplicationArguments對象中供ApplicationRunner調(diào)用??匆幌?code>ApplicationArguments的相關(guān)方法:

  • getSourceArgs() 被傳遞給應(yīng)用程序的原始參數(shù),返回這些參數(shù)的字符串數(shù)組。
  • getOptionNames() 獲取選項名稱的Set字符串集合。如 --spring.profiles.active=dev --debug 將返回["spring.profiles.active","debug"] 。
  • getOptionValues(String name) 通過名稱來獲取該名稱對應(yīng)的選項值。如--foo=bar --foo=baz 將返回["bar","baz"]。
  • containsOption(String name) 用來判斷是否包含某個選項的名稱。
  • getNonOptionArgs() 用來獲取所有的無選項參數(shù)。

可以通過下面的命令運行一個 Spring Boot應(yīng)用 Jar

java -jar yourapp.jar --foo=bar --foo=baz --dev.name=fcant java fcantcn

或者在IDEA開發(fā)工具中打開Spring Boot應(yīng)用main方法的配置項,進行命令行參數(shù)的配置,其他IDE工具同理。
運行Spring Boot應(yīng)用,將會打印出:

2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --foo=bar
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --foo=baz
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --dev.name=fcant
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = java
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = fcantcn
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.LowOrderCommandLineRunner    : i am lowOrderRunner
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : i am applicationRunner
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : optionNames = [dev.name, foo]
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : sourceArgs = [--foo=bar, --foo=baz, --dev.name=fcant, java, fcantcn]
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : nonOptionArgs = [java, fcantcn]
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : optionValues = [bar, baz]

然后就可以根據(jù)實際需要動態(tài)地執(zhí)行一些邏輯。 

4、源碼跟蹤

通過源碼理解一下底層實現(xiàn)。 

run()方法

跟進run方法后,一路F6直達以下方法

public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   //設(shè)置線程啟動計時器
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   //配置系統(tǒng)屬性:默認缺失外部顯示屏等允許啟動
   configureHeadlessProperty();
   //獲取并啟動事件監(jiān)聽器,如果項目中沒有其他監(jiān)聽器,則默認只有EventPublishingRunListener
   SpringApplicationRunListeners listeners = getRunListeners(args);
   //將事件廣播給listeners
   listeners.starting();
   try {
       //對于實現(xiàn)ApplicationRunner接口,用戶設(shè)置ApplicationArguments參數(shù)進行封裝
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
      //配置運行環(huán)境:例如激活應(yīng)用***.yml配置文件      
      ConfigurableEnvironment environment = prepareEnvironment(listeners,
            applicationArguments);
      configureIgnoreBeanInfo(environment);
      //加載配置的banner(gif,txt...),即控制臺圖樣
      Banner printedBanner = printBanner(environment);
      //創(chuàng)建上下文對象,并實例化
      context = createApplicationContext();
      exceptionReporters = getSpringFactoriesInstances(
            SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      //配置SPring容器      
      prepareContext(context, environment, listeners, applicationArguments,
            printedBanner);
      //刷新Spring上下文,創(chuàng)建bean過程中      
      refreshContext(context);
      //空方法,子類實現(xiàn)
      afterRefresh(context, applicationArguments);
      //停止計時器:計算線程啟動共用時間
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass)
               .logStarted(getApplicationLog(), stopWatch);
      }
      //停止事件監(jiān)聽器
      listeners.started(context);
      //開始加載資源
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      handleRunFailure(context, listeners, exceptionReporters, ex);
      throw new IllegalStateException(ex);
   }
   listeners.running(context);
   return context;
}

主要是熟悉SpringBoot的CommandLineRunner接口實現(xiàn)原理。因此上面SpringBoot啟動過程方法不做過多介紹。直接進入CallRunners()方法內(nèi)部。 

callRunners方法

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    //將實現(xiàn)ApplicationRunner和CommandLineRunner接口的類,存儲到集合中
   List<Object> runners = new ArrayList<>();
   runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
   runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
   //按照加載先后順序排序
   AnnotationAwareOrderComparator.sort(runners);
   for (Object runner : new LinkedHashSet<>(runners)) {
      if (runner instanceof ApplicationRunner) {
         callRunner((ApplicationRunner) runner, args);
      }
      if (runner instanceof CommandLineRunner) {
         callRunner((CommandLineRunner) runner, args);
      }
   }
}
private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
   try {
       //調(diào)用各個實現(xiàn)類中的邏輯實現(xiàn)
      (runner).run(args.getSourceArgs());
   }
   catch (Exception ex) {
      throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
   }
}

到此結(jié)束,再跟進run()方法,就可以看到資源加載邏輯。

到此這篇關(guān)于SpringBoot 中 CommandLineRunner的作用的文章就介紹到這了,更多相關(guān)SpringBoot 中 CommandLineRunner內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳細了解java監(jiān)聽器和過濾器

    詳細了解java監(jiān)聽器和過濾器

    下面小編就為大家?guī)硪黄趈ava servlet過濾器和監(jiān)聽器(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-07-07
  • Spring Profiles使用方法詳解

    Spring Profiles使用方法詳解

    在你剛接觸SpringBoot的時候有沒有對它提供的Profile有些許不適應(yīng),經(jīng)過摸索后才領(lǐng)悟到它的強大。今天我就對Profile進行一點歸納總結(jié),留作互聯(lián)網(wǎng)記憶
    2022-12-12
  • Java基于堆結(jié)構(gòu)實現(xiàn)優(yōu)先隊列功能示例

    Java基于堆結(jié)構(gòu)實現(xiàn)優(yōu)先隊列功能示例

    這篇文章主要介紹了Java基于堆結(jié)構(gòu)實現(xiàn)優(yōu)先隊列功能,結(jié)合實例形式分析了java優(yōu)先隊列的簡單定義與使用方法,需要的朋友可以參考下
    2017-11-11
  • Springboot把外部依賴包納入Spring容器管理的兩種方式

    Springboot把外部依賴包納入Spring容器管理的兩種方式

    這篇文章主要給大家介紹了Springboot把外部依賴包納入Spring容器管理的兩種方式,Spring.factories和org.springframework.boot.autoconfigure.AutoConfiguration.imports,有感興趣的小伙伴可以參考閱讀本文
    2023-07-07
  • 通過FeignClient如何獲取文件流steam?is?close問題

    通過FeignClient如何獲取文件流steam?is?close問題

    這篇文章主要介紹了通過FeignClient如何獲取文件流steam?is?close問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java本地高性能緩存的幾種常見實現(xiàn)方式

    Java本地高性能緩存的幾種常見實現(xiàn)方式

    在Java中緩存是一種常用的性能優(yōu)化技術(shù),用于在應(yīng)用程序中加速訪問和查詢數(shù)據(jù)的速度,下面這篇文章主要給大家介紹了關(guān)于Java本地高性能緩存的幾種常見實現(xiàn)方式,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-07-07
  • Linux服務(wù)器如何部署java項目

    Linux服務(wù)器如何部署java項目

    這篇文章主要介紹了Linux服務(wù)器如何部署java項目問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • HttpClient的KeepAlive接口方法源碼解析

    HttpClient的KeepAlive接口方法源碼解析

    這篇文章主要為大家介紹了HttpClient的KeepAlive接口方法源碼解析,
    有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • 關(guān)于報錯IDEA Terminated with exit code 1的解決方法

    關(guān)于報錯IDEA Terminated with exit code 

    如果在IDEA構(gòu)建項目時遇到下面這樣的報錯IDEA Terminated with exit code 1,那必然是Maven的設(shè)置參數(shù)重置了,導致下載錯誤引起的,本文給大家分享兩種解決方法,需要的朋友可以參考下
    2022-08-08
  • 系統(tǒng)運維問題排查-java內(nèi)存過高分析及說明

    系統(tǒng)運維問題排查-java內(nèi)存過高分析及說明

    本文總結(jié)了監(jiān)控Java進程內(nèi)存與線程狀態(tài)的常用命令及參數(shù),包括top排序、jmap查看內(nèi)存分布、jstat分析GC數(shù)據(jù)、jstack解析線程狀態(tài)等,強調(diào)需使用與進程一致的用戶執(zhí)行,并解析了線程狀態(tài)和內(nèi)存區(qū)域的含義
    2025-07-07

最新評論

德惠市| 巍山| 伊金霍洛旗| 蛟河市| 稷山县| 开江县| 宜城市| 平罗县| 新津县| 白银市| 德清县| 鸡西市| 阳朔县| 临城县| 阿拉善盟| 栾城县| 雷山县| 旺苍县| 牡丹江市| 江西省| 上杭县| 岳阳县| 璧山县| 湖北省| 新余市| 永昌县| 阿坝县| 北安市| 淅川县| 徐州市| 余姚市| 子洲县| 沙湾县| 绿春县| 苍梧县| 绥棱县| 大埔县| 高雄市| 营山县| 阿拉善盟| 海门市|