Springboot ApplicationRunner的使用解读
作者:澄风
Springboot ApplicationRunner使用
ApplicationRunner介绍
ApplicationRunner是在应用容器启动之后会回调到,在ApplicationStartedListener调用之后被调用。
如果说ApplicationListener中有阻塞,那么ApplicationRunner也都不会被调用。
@Component public class ApplicationRunnerTest implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println(args); } }
我们可以在applicationRunner中做一些异步启动的操作,比如实例化Kafka客户端,异步加载缓存等等在服务启动之后不立马提供服务的操作。
通过分析源码可以知道runner实在容器加载完成以及ApplicationStartedListener调用之后进行回调的。
ApplicationRunner为什么不被调用
问题描述
在项目中写了一个ApplicationRunner 来启动消费队列线程,结果启动的时候applicationRunner的run方法死活不被调用。
问题分析
通过debug发现,在springboot初始化完环境refresh context之后就会调用started listener然后调用application runner,如果started listner 存在阻塞的话就会导致后续的application runner 不被运行。
而我在另一个组件中使用ApplicationListener<ApplicationStartedEvent> 去启动了netty server,启动netty server会导致当前线程阻塞以至于application runner 不被调用。
问题解决
在listener和Runner当中尽量启用线程来跑阻塞而不是直接去跑阻塞任务。
ApplicationRunner的作用是什么?
有时针对一些特殊的业务场景,需要在系统启动时执行某些任务,如:配置文件的加载、数据库的初始化等等操作。
SpringBoot 提供了两种解决方案:
- 一种是使用CommandLineRunner
- 另一种是使用 ApplicationRunner
基本原理
项目在启动时会遍历所有的 ApplicationRunner 的实现类并调用其中的 run 方法,如果在系统中有多个 ApplicationRunner的实现类,可以使用 @Order 注解对这些实现类的调用顺序进行排序(数字越小越先执行);run方法的参数是系统启动时传入的参数,即入口类中main方法的参数(在调用SpringApplication.run方法时传入到 SpringBoot项目的上下文环境中)。
如何使用
@Component @Slf4j @Order(1) public class MyApplicationRunner implements ApplicationRunner { // ApplicationArguments, 需要区分选项参数和非选项参数; // 选项参数, 通过ApplicationArguments的getOptionNames()方法获取所有选项名称即参数的KEY, 然后通过 getOptionValues()方法根据参数KEY, 获取实际值(它会返回一个列表字符串), 一般为: --user-name=ROCKY --age=30 // 非选项参数, 通过ApplicationArguments的getNonOptionArgs()方法获取一个参数值数组; @Override public void run(ApplicationArguments args) throws Exception { // TO DO SOMETHING... } }
ApplicationRunner和CommandLineRunner的区别
@Component @Slf4j @Order(1) public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { // TO DO SOMETHING... } }
ApplicationRunner与CommandLineRunner的主要区别体现在run方法的参数上,CommandLineRunner中的run方法的参数是参数数组;ApplicationRunner中的run方法的参数是ApplicationArguments对象。
执行顺序
系统支持创建多个CommandLineRunner或ApplicationRunner的实现类,可以使用@Order注解或实现Ordered接口,来设定各个实现类的执行顺序。
选项参数与非选项参数
- 选项参数:可以理解为Spring Boot 提供的参数格式,以–开头,使用=分割键值对,如:java -jar XXX.jar --name=ROCKY --age=30 --spring.profiles.active=dev;
- 非选项参数:不是以–开头,也没有设置值的单一参数KEY只有值,如:java -jar XXX.jar --name=ROCKY --age=30 --spring.profiles.active=dev 陕西 西安 雁塔区,其中"陕西 西安 雁塔区" 就是非选项参数;
- 系统参数:-Dxxxx是设置JAVA运行上下文的参数语法,用于配置一些环境变量,如:java -jar XXX.jar -Dserver.port=8081 --name=ROCKY --age=30 --spring.profiles.active=dev 陕西 西安 雁塔区,其中"-Dserver.port"就是系统参数。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。