本文主要是介绍SpringBoot日常:扩展接口之CommandLineRunner和ApplicationRunner,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 简介
- springboot启动容器过程
- 应用场景
- 如何控制执行顺序
- ApplicationRunner和CommandLineRunner区别
- 代码示例
- 运行示例
简介
日常开发中我们可能经常会遇到这样的场景,像启动容器完成后需要去执行一些业务逻辑,SpringBoot给我们提供了两个接口来帮助我们实现这种需求,两个启动加载接口分别是CommandLineRunner和ApplicationRunner。本文简单介绍如何使用该扩展点实现业务
springboot启动容器过程
首先我们来看看springboot启动容器过程源码,从下列源码启动过程可以看到,在所有事项准备完成后,最终会执行所有 Runner 运行器,其中就包括ApplicationRunner和CommandLineRunner
/*** Run the Spring application, creating and refreshing a new* {@link ApplicationContext}.* @param args the application arguments (usually passed from a Java main method)* @return a running {@link ApplicationContext}*/
public ConfigurableApplicationContext run(String... args) {// 获取系统时间,开始计时器long startTime = System.nanoTime();DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;configureHeadlessProperty();// 创建所有 Spring 运行监听器并发布应用启动事件SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);try {// 处理 args 参数ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 准备环境ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);// 创建应用上下文context = createApplicationContext();context.setApplicationStartup(this.applicationStartup);// 准备应用上下文prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 刷新应用上下文refreshContext(context);// 应用上下文刷新之后的事件的处理afterRefresh(context, applicationArguments);Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}// 发布应用上下文启动完成事件listeners.started(context, timeTakenToStartup);// 执行所有 Runner 运行器callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);// 发布应用上下文就绪事件listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;
}
private void callRunners(ApplicationContext context, ApplicationArguments args) {//将实现ApplicationRunner和CommandLineRunner接口的类,存储到集合中List<Object> runners = new ArrayList<>();// 从Spring容器中查找类型为ApplicationRunner的Beanrunners.addAll(context.getBeansOfType(ApplicationRunner.class).values());// 从Spring容器中查找类型为CommandLineRunner的Beanrunners.addAll(context.getBeansOfType(CommandLineRunner.class).values());//按照加载先后顺序排序AnnotationAwareOrderComparator.sort(runners);//调用执行for (Object runner : new LinkedHashSet<>(runners)) {//如果是ApplicationRunner的实例if (runner instanceof ApplicationRunner) {callRunner((ApplicationRunner) runner, args);}//如果是CommandLineRunner的实例if (runner instanceof CommandLineRunner) {callRunner((CommandLineRunner) runner, args);}}
}
应用场景
ApplicationRunner和CommandLineRunner实在容器启动完成后才执行,所以常常会用在一些初始化的场景,比如
- 缓存数据的预加载
- 定时任务的执行
- 升级脚本的数据刷新
- …
如何控制执行顺序
如果存在多个实现类,可以通过注解@Order注解或实现Ordered接口来控制执行顺序
@Order(2)
public class aaaCommandLineRunner implements CommandLineRunner {
ApplicationRunner和CommandLineRunner区别
ApplicationRunner和CommandLineRunner的作用是相同的。不同之处在于ApplicationRunner接口的run()方法接收ApplicationArguments对象作为参数,是对原始参数做了进一步的封装,而CommandLineRunner接口的run()方法接收String数组作为参数,即是最原始的参数,没有做任何处理。
代码示例
@Slf4j
@Configuration
public class ExtendApplicationRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {log.info("ApplicationRunner--Extend--run {}",args);}
}
@Slf4j
@Configuration
@Order(2)
public class ExtendCommandLineRunner implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {log.info("CommandLineRunner--Extend--run{}",args);}
}
运行示例
这篇关于SpringBoot日常:扩展接口之CommandLineRunner和ApplicationRunner的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!