SpringBoot实现多个ApplicationRunner时部分接口未执行问题
作者:惊虹上的小白
SpringBoot多个ApplicationRunner时部分接口未执行
在springboot的项目中,需要在容器启动之后执行一些操作。springboot提供了ApplicationRunner和CommandLineRunner两个接口可以帮助我们实现这种需求。
当项目中实现了多个ApplicationRunner接口,并且其中一个使用了类似于while(true)这样不会退出的循环体。将会导致后续的ApplicationRunner接口不会被调用。
如下:
@Component @Slf4j public class RunnerTest1 implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { while (true) { System.out.println("this is RunnerTest1"); Thread.sleep(100); } } }
@Component @Slf4j public class RunnerTest2 implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { while (true) { System.out.println("this is RunnerTest2"); Thread.sleep(100); } } }
输出结果:
可以看到项目启动后RunnerTest2 将不会被执行。
通过分析springboot启动的源码可以发现,在applicationContext容器加载完成之后,会调用SpringApplication类的callRunners方法
该方法中会获取所有实现了ApplicationRunner和CommandLineRunner的接口bean,然后依次执行对应的run方法,并且是在同一个线程中执行。
因此如果有某个实现了ApplicationRunner接口的bean的run方法一直循环不返回的话,后续的代码将不会被执行。
ApplicationRunner实现项目启动就执行的功能
ApplicationRunner
是一个接口,常用于项目启动后,(也就是ApringApplication.run()执行结束),立马执行某些逻辑。
可用于项目的准备工作,比如加载配置文件,加载执行流,定时任务等等。
如何使用ApplicationRunner
这里有几点说明:
- 1:这个实现类,要注入到spring容器中,这里使用了@Component注解;
- 2:在同一个项目中,可以定义多个ApplicationRunner的实现类,他们的执行顺序通过注解@Order注解或者再实现Ordered接口来实现。
- 3:run方法的参数:ApplicationArguments可以获取到当前项目执行的命令参数。(比如把这个项目打成jar执行的时候,带的参数可以通过ApplicationArguments获取到);
- 4:由于该方法是在容器启动完成之后,才执行的,所以,这里可以从spring容器中拿到其他已经注入的bean。
(可以有多个实例实现该接口,但是一般需要增加注解@Order来指定加载顺序)
@Component @Order(2) public class JDDRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println(args); System.out.println("这个是测试ApplicationRunner接口"); } }
实现ApplicationRunner接口,重写run方法,定义具体的执行逻辑
@Order注解,用于决定多个bean的执行顺序,按照值从小到大执行 (值可为负数)
- @Order(-1)优先于@Order(0)
- @Order(1)优先于@Order(2)
还有个接口
也可以实现和ApplicationRunner一样的功能
- CommandLineRunner
- CommandLineRunner接口的run方法接收的参数为String数组
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。