欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot 中 CommandLineRunner的作用示例詳解

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

1、CommandLineRunner

SpringBoot中CommandLineRunner的作用

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

簡單例子

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("項(xiàng)目已經(jīng)啟動");
    }
}

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

通過實(shí)現(xiàn)Ordered接口實(shí)現(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注解實(shí)現(xiàn)控制執(zhí)行順序

SpringBoot在項(xiàng)目啟動后會遍歷所有實(shí)現(xiàn)CommandLineRunner的實(shí)體類并執(zhí)行run方法,如果需要按照一定的順序去執(zhí)行,那么就需要在實(shí)體類上使用一個(gè)@Order注解(或者實(shí)現(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 作用

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

2、ApplicationRunner

在Spring Boot 1.3.0又引入了一個(gè)和CommandLineRunner功能一樣的接口ApplicationRunner。CommandLineRunner接收可變參數(shù)String... args,而ApplicationRunner 接收一個(gè)封裝好的對象參數(shù)ApplicationArguments。除此之外它們功能完全一樣,甚至連方法名都一樣。聲明一個(gè)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;
    }
}

按照順序打印了三個(gè)類的執(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í)是可以接受參數(shù)的,換句話說也就是Spring Bootmain方法是可以接受參數(shù)的。這些參數(shù)通過命令行 java -jar yourapp.jar 來傳遞。CommandLineRunner會原封不動照單全收這些接口,這些參數(shù)也可以封裝到ApplicationArguments對象中供ApplicationRunner調(diào)用??匆幌?code>ApplicationArguments的相關(guān)方法:

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

可以通過下面的命令運(yùn)行一個(gè) 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方法的配置項(xiàng),進(jìn)行命令行參數(shù)的配置,其他IDE工具同理。
運(yùn)行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ù)實(shí)際需要動態(tài)地執(zhí)行一些邏輯。 

4、源碼跟蹤

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

run()方法

跟進(jìn)run方法后,一路F6直達(dá)以下方法

public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   //設(shè)置線程啟動計(jì)時(shí)器
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   //配置系統(tǒng)屬性:默認(rèn)缺失外部顯示屏等允許啟動
   configureHeadlessProperty();
   //獲取并啟動事件監(jiān)聽器,如果項(xiàng)目中沒有其他監(jiān)聽器,則默認(rèn)只有EventPublishingRunListener
   SpringApplicationRunListeners listeners = getRunListeners(args);
   //將事件廣播給listeners
   listeners.starting();
   try {
       //對于實(shí)現(xiàn)ApplicationRunner接口,用戶設(shè)置ApplicationArguments參數(shù)進(jìn)行封裝
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
      //配置運(yùn)行環(huán)境:例如激活應(yīng)用***.yml配置文件      
      ConfigurableEnvironment environment = prepareEnvironment(listeners,
            applicationArguments);
      configureIgnoreBeanInfo(environment);
      //加載配置的banner(gif,txt...),即控制臺圖樣
      Banner printedBanner = printBanner(environment);
      //創(chuàng)建上下文對象,并實(shí)例化
      context = createApplicationContext();
      exceptionReporters = getSpringFactoriesInstances(
            SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      //配置SPring容器      
      prepareContext(context, environment, listeners, applicationArguments,
            printedBanner);
      //刷新Spring上下文,創(chuàng)建bean過程中      
      refreshContext(context);
      //空方法,子類實(shí)現(xiàn)
      afterRefresh(context, applicationArguments);
      //停止計(jì)時(shí)器:計(jì)算線程啟動共用時(shí)間
      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接口實(shí)現(xiàn)原理。因此上面SpringBoot啟動過程方法不做過多介紹。直接進(jìn)入CallRunners()方法內(nèi)部。 

callRunners方法

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    //將實(shí)現(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)用各個(gè)實(shí)現(xiàn)類中的邏輯實(shí)現(xiàn)
      (runner).run(args.getSourceArgs());
   }
   catch (Exception ex) {
      throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
   }
}

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

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

相關(guān)文章

  • Spring MVC異常處理機(jī)制示例詳解

    Spring MVC異常處理機(jī)制示例詳解

    這篇文章主要給大家介紹了關(guān)于Spring MVC異常處理機(jī)制的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Spring MVC具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • Java超詳細(xì)教你寫一個(gè)學(xué)籍管理系統(tǒng)案例

    Java超詳細(xì)教你寫一個(gè)學(xué)籍管理系統(tǒng)案例

    這篇文章主要介紹了怎么用Java來寫一個(gè)學(xué)籍管理系統(tǒng),學(xué)籍管理主要涉及到學(xué)生信息的增刪查改,本篇將詳細(xì)的實(shí)現(xiàn),感興趣的朋友跟隨文章往下看看吧
    2022-03-03
  • Spring Cloud OpenFeign REST服務(wù)客戶端原理及用法解析

    Spring Cloud OpenFeign REST服務(wù)客戶端原理及用法解析

    這篇文章主要介紹了Spring Cloud OpenFeign REST服務(wù)客戶端原理及用法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • java求100之內(nèi)的素?cái)?shù)(質(zhì)數(shù))簡單示例

    java求100之內(nèi)的素?cái)?shù)(質(zhì)數(shù))簡單示例

    這篇文章主要介紹了java求100之內(nèi)的素?cái)?shù)簡單示例,素?cái)?shù)是一個(gè)大于1的自然數(shù),如果除了1和它自身外,不能被其他自然數(shù)整除的數(shù);否則稱為合數(shù)
    2014-04-04
  • 一起因MySQL時(shí)間戳精度引發(fā)的血案分析

    一起因MySQL時(shí)間戳精度引發(fā)的血案分析

    這篇文章主要給大家介紹了一起因MySQL時(shí)間戳精度引發(fā)的血案的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • springboot全局異常處理代碼實(shí)例

    springboot全局異常處理代碼實(shí)例

    這篇文章主要介紹了springboot全局異常處理代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Spring-Security對HTTP相應(yīng)頭的安全支持方式

    Spring-Security對HTTP相應(yīng)頭的安全支持方式

    這篇文章主要介紹了Spring-Security對HTTP相應(yīng)頭的安全支持方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • JAVA對字符串進(jìn)行32位MD5加密的實(shí)踐

    JAVA對字符串進(jìn)行32位MD5加密的實(shí)踐

    本文主要介紹了JAVA對字符串進(jìn)行32位MD5加密的實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • 一文解析Java中的方法重寫

    一文解析Java中的方法重寫

    子類繼承父類后,可以在子類中書寫一個(gè)與父類同名同參的方法,從而實(shí)現(xiàn)對父類中同名同參數(shù)的方法的覆蓋,我們把這一過程叫做方法的重寫。本文將分析一下Java中的方法重寫,感興趣的可以了解一下
    2022-07-07
  • mybatis plus in方法使用說明

    mybatis plus in方法使用說明

    這篇文章主要介紹了mybatis plus in方法使用說明,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11

最新評論