在我们用 springboot 搭建项目的时候,有时候会碰到在项目启动时初始化一些操作的需求 ,针对这种需求 spring boot为我们提供了以下几种方案供我们选择:
ApplicationRunner与 CommandLineRunner接口
Spring容器初始化时InitializingBean接口和@PostConstruct
Spring的事件机制
ApplicationRunner与CommandLineRunner
我们可以实现 ApplicationRunner或 CommandLineRunner接口, 这两个接口工作方式相同,都只提供单一的run方法,该方法在SpringApplication.run(…)完成之前调用,不知道大家还对我上一篇文章结尾有没有印象,我们先来看看这两个接口
public interfaceApplicationRunner {void run(ApplicationArguments var1) throwsException;
}public interfaceCommandLineRunner {void run(String... var1) throwsException;
}
都只提供单一的run方法,接下来我们来看看具体的使用
ApplicationRunner
构造一个类实现ApplicationRunner接口
//需要加入到Spring容器中
@Componentpublic class ApplicationRunnerTest implementsApplicationRunner {
@Overridepublic void run(ApplicationArguments args) throwsException {
System.out.println("ApplicationRunner");
}
}
很简单,首先要使用@Component将实现类加入到Spring容器中,为什么要这样做我们待会再看,然后实现其run方法实现自己的初始化数据逻辑就可以了
CommandLineRunner
对于这两个接口而言,我们可以通过Order注解或者使用Ordered接口来指定调用顺序, @Order()中的值越小,优先级越高
//需要加入到Spring容器中@Component
@Order(1)public class CommandLineRunnerTest implementsCommandLineRunner {
@Overridepublic void run(String... args) throwsException {
System.out.println("CommandLineRunner...");
}
}
同样需要加入到Spring容器中,CommandLineRunner的参数是最原始的参数,没有进行任何处理,ApplicationRunner的参数是ApplicationArguments,是对原始参数的进一步封装
源码分析
private voidcallRunners(ApplicationContext context, ApplicationArguments args) {
List runners = new ArrayList();//获取容器中所有的ApplicationRunner的Bean实例
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());//获取容器中所有的CommandLineRunner的Bean实例
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);for (Object runner : new LinkedHashSet(runners)) {if (runner instanceofApplicationRunner) {//执行ApplicationRunner的run方法callRunner((ApplicationRunner) runner, args);
}if (runner instanceofCommandLineRunner) {//执行CommandLineRunner的run方法callRunner((CommandLineRunner) runner, args);
}
}
}
很明显,是直接从Spring容器中获取ApplicationRunner和CommandLineRunner的实例,并调用其run方法,这也就是为什么我