在实际项目开发过程当中,有时候须要在服务启动时进行一些业务初始化操做,这些操做只须要在服务启动后执行一次,那么经过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