【SpringBoot】为什么我的 CommandLineRunner 不 run ?
Springboot 工程中通常都有几个
CommandLineRunner
的实现类,用来在程序启动之后干点什么。但如果使用不当,可能就会发现有的 Runner 在程序启动之后执行了,有的却没有执行,更奇怪的是程序也没有报错。原因就是...
先看现象
假设一个工程中需要用到 3 个 CommandLineRunner, 其中 2 个 runner 需要执行一个 while(true) 循环
代码如下:
程序运行之后 你会发现 Runner2 和 Runnner3 总会有一个不运行,甚至 Runner1 也不运行,但是程序也不报错,怎么回事?
透过本质看现象
是的,先看 CommandLineRunner
是怎么执行的才能知道错在了哪里从而解决这个问题。
CommandLineRunner.java
注释第一句话表示:实现了这个接口的一个 spring bean 在程序启动之后应该 run
.
这里的 run 用了 <em>
标签进行了强调,为什么?不着急回答,再往下看 看看 CommandLineRunner 是如何被Spring Boot 执行的...
SpringApplication.java
接下来看看 SpringApplication
这个类的注释信息:
从这个注释可以知道,SpringApplication
负责触发所有 CommandLineRunner
的运行。到代码部分,就是下面的几个方法:
callRunners()
callRunner()
callRunners 负责从上下文中获取到所有 CommandLineRunner 的实现类,循环遍历,对于每一个实现类对象,调用 callRunner 方法进行触发。而在 callRunner 方法中同步执行的是 runner 对象的 run 方法.
到此,答案已经很清晰了,CommandLineRunner 不 run ,或者有的 run 有的不 run,程序也不报错的原因就是:
你有多个 CommandLineRunner 的实现类
在某个实现类的 run 方法体中调用了同步阻塞的API或者是一个 while(true) 循环
这样就导致了 SpringApplication 在执行这个 run 方法时阻塞,无法继续执行循环中的下一个 runner 的 run 方法。
为了避免程序中犯这个错,一定要记住,
CommandLineRunner != Runnable
CommandLineRunner != Runnable
CommandLineRunner != Runnable
虽然这两个接口都有一个 run 方法,很容易让人理解成一个 CommandLineRunner 就会对应一个线程。NO!
知错就改
对于 Runner1 不需要做任何修改。
对于 Runner2 和 Runner3,需要做以下修改,让 while(true) 循环不阻塞 run 方法的运行即可。
版权声明: 本文为 InfoQ 作者【遇见】的原创文章。
原文链接:【http://xie.infoq.cn/article/2b2052f6098b570c63298624e】。文章转载请联系作者。
评论