Spring Boot启动后自动执行任务解决方案
1.需求来源
日常开发中有时会要求 Spring 容器启动完成后,初始化一些资源加载,例如:解析配置文件完成 es 数据初始化或增量更新,自定义线程池初始化等工作。
2.解决方案
SpringBoot 给我们提供了两个接口来帮助我们实现这种需求。这两个接口分别为 CommandLineRunner和 ApplicationRunner。他们的执行时机为容器启动完成的时候。这两个接口中有一个 run 方法,我们只需要实现这个方法即可。这两个接口的不同之处在于:ApplicationRunner 中 run 方法的参数为ApplicationArguments,而 CommandLineRunner 接口中 run 方法的参数为 String 数组。
2.1.实现 CommandLineRunner 接口
@Slf4j
@Component
public class InitCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
log.info("读取String数组参数初始化操作内容...");
}
}
项目启动效果
... 前面内容省略
2021-09-27 23:09:18.994 INFO 47408 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-09-27 23:09:18.995 INFO 35420 --- [ restartedMain] c.g.v.m.explorer.ExplorerApplication : Started ExplorerApplication in 3.169 seconds (JVM running for 4.664)
2021-09-27 23:09:18.996 INFO 35420 --- [ restartedMain] c.g.v.m.e.runner.InitCommandLineRunner : 读取String数组参数初始化操作内容...
2.2.实现 ApplicationRunner 接口
@Slf4j
@Component
public class InitApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("读取 ApplicationArguments 获取项目详细信息初始化操作内容...");
}
}
项目启动效果
... 前面内容省略
2021-09-27 23:10:16.541 INFO 47408 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-09-27 23:10:16.542 INFO 35420 --- [ restartedMain] c.g.v.m.explorer.ExplorerApplication : Started ExplorerApplication in 3.169 seconds (JVM running for 4.664)
2021-09-27 23:10:16.543 INFO 35420 --- [ restartedMain] c.g.v.m.e.runner.InitApplicationRunner : 读取 ApplicationArguments 获取项目详细信息初始化操作内容...
2.3.顺序要求–@Order
注解
实际开发中存储初始化加载执行顺序的要求场景,此时就可以使用 @Order
注解,它可以为多个在 spring 容器启动完成后,将接下来的 Runner 任务 按照排序 串行执行。例如:加了@Order(1)
注解的类实例 bean 优先于@Order(2)
注解的类实例 bean。
... 前面内容省略
2021-09-27 23:14:08.790 INFO 47408 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-09-27 23:14:08.792 INFO 47408 --- [ restartedMain] c.g.v.m.explorer.ExplorerApplication : Started ExplorerApplication in 3.164 seconds (JVM running for 4.195)
2021-09-27 23:14:08.793 INFO 47408 --- [ restartedMain] c.g.v.m.e.runner.InitCommandLineRunner : 读取String数组参数初始化操作内容...
2021-09-27 23:14:08.793 INFO 47408 --- [ restartedMain] c.g.v.m.e.runner.InitCommandLineRunner : @Order(1)
2021-09-27 23:14:08.793 INFO 47408 --- [ restartedMain] c.g.v.m.e.runner.InitApplicationRunner : 读取 ApplicationArguments 获取项目详细信息初始化操作内容...
2021-09-27 23:14:08.793 INFO 47408 --- [ restartedMain] c.g.v.m.e.runner.InitApplicationRunner : @Order(2)
2.4.实际生产运用案例
1、初始化ES,同步表数据
/**
* 初始化 需要同步数据到 ES index的数据
*/
@Slf4j
@Component
@Order(value = 2)
public class DataInitRunner implements ApplicationRunner {
@Autowired
private InitTables initTables;
@Autowired
private InitTablesDataService initTablesDataService;
/**
* 初始化es index
*/
@Override
public void run(ApplicationArguments args) {
try {
initTables.getList().forEach(initTablesDataService::initTablesData);
log.info("elasticsearch同步数据成功...");
} catch (Exception e) {
e.printStackTrace();
log.error("elasticsearch同步数据失败...");
}
}
}
2、初始化本地存储路径
@Slf4j
@Component
@Order(1)
public class FilePathInitRunner implements ApplicationRunner {
@Autowired
private ExplorerConfig explorerConfig;
public void run(ApplicationArguments args) throws Exception {
File file = new File(explorerConfig.getRootDir());
if (!file.exists()) {
file.mkdirs();
log.info("路径不存在,创建完成");
}
log.info("路径初始化完成");
}
}
以上方案说明结束。