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