在實際項目開發過程當中,有時候須要在服務啓動時進行一些業務初始化操做,這些操做只須要在服務啓動後執行一次,那麼經過Spring Boot如何實現該需求呢? Spring Boot提供了ApplicationRunner和CommandLineRunner兩種服務接口,這兩種服務接口均可以實現上面的業務需求,本文將對這兩種服務接口實現進行介紹。git
相同點spring
不一樣點app
不少誤認爲CommandLineRunner會先於ApplicationRunner執行,可是實際上二者是一塊兒觸發執行的,能夠閱讀SpringApplication.class方法中的源碼less
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); Banner printedBanner = this.printBanner(environment); context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); Iterator var4 = (new LinkedHashSet(runners)).iterator(); while(var4.hasNext()) { Object runner = var4.next(); if (runner instanceof ApplicationRunner) { this.callRunner((ApplicationRunner)runner, args); } if (runner instanceof CommandLineRunner) { this.callRunner((CommandLineRunner)runner, args); } } }
@Component @Slf4j public class ApplicationRunnerFirst implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { log.info("This is {} Application Runner", "first"); } }
@Component @Slf4j public class ApplicationRunnerSecond implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { log.info("This is {} Application Runner", "second"); } }
@Component @Slf4j public class CommandlineRunnerFirst implements CommandLineRunner { @Override public void run(String... args) throws Exception { log.info("CommandLineRunner Args:{}",JSON.toJSONString(args)); log.info("This is {} Command Line Runner", "first"); } }
@Component @Slf4j public class CommandlineRunnerSecond implements CommandLineRunner { @Override public void run(String... args) throws Exception { log.info("This is {} Command Line Runner", "second"); } }
可使用org.springframework.core.annotation.Order註解設置執行順序,其中數值越小越優先執行。例如:ide
@Component @Slf4j @Order(3) public class ApplicationRunnerFirst implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { log.info("ApplicationRunner Args:{}",JSON.toJSONString(args)); log.info("This is {} Application Runner", "first"); } }
分別將CommandlineRunnerSecond的Order設置爲1,ApplicationRunnerSecond設置爲2,ApplicationRunnerFirst設置爲3,CommandlineRunnerFirst不設置。spring-boot
啓動服務,運行結果以下:this
你會發現,未指定順序的CommandlineRunnerFirst在最後執行,那是由於若是沒有設置順序,運行時排序使用的數值是整型最大值2147483647(@Order註解的默認值也是整型最大值),詳細可閱讀OrderComparator.class源碼。 還有需注意的是,Runner的實現類必須註冊爲Spring Bean,不然不回被執行,閱讀SpringApplication.run方法的源碼就知道緣由了。命令行
碼雲:https://gitee.com/centy/spring-boot-examples/tree/master/spring-boot-examples-runner日誌
不管ApplicationRunner仍是CommandLineRunner,都是在應用啓動完成後執行一次業務初始化代碼,達到的效果也比較相似,因爲ApplicationRunner的方法參數是ApplicationArguments對象,使用起來更加方便,因此更推薦使用。code