一、概述
在我们的日常开发中会有这样的场景,在容器启动完成之后去做一些事,例如:数据库初始化、缓存预热、启动后检查、任务调度等。 SpringBoot给我们提供了两个接口来帮助我们实现这种需求,分别是:ApplicationRunner和 CommandLineRunner。
这两个接口的主要区别是参数传递方式不同。ApplicationRunner接口的run()方法有一个ApplicationArguments类型的参数,CommandLineRunner接口的run()方法有一个String数组类型的参数。
二、源码
我们跟着启动类的run方法进去,来到SpringApplication的run方法中
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//刷新上下文
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
//调用Runners
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
第32行callRunners方法就是调用ApplicationRunner与CommandLineRunner的入口,可以看到是在容器启动完成之后调用的,我们进去看下
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
//添加所有ApplicationRunner接口的实例
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
//添加所有CommandLineRunner接口的实例
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);
}
}
}
callRunners方法主要就是获取ApplicationRunner与CommandLineRunner接口的实例,并按照Order排序后循环执行callRunner方法
三、示例
下面我们写两个例子看看
@Component
@Order(1)
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("MyCommandLineRunner......run");
}
}
@Component
@Order(2)
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("MyApplicationRunner......run");
}
}
启动后日志如下
MyCommandLineRunner……run
MyApplicationRunner……run
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/154500.html