How to resolve springboot CommandLineRunner run not called problem?
1. The purpose of this post
When using CommandLineRunner
in Spring Boot applications, we expect its run
method to be called when the application starts. However, sometimes the run
method is not called, even if the code and settings appear correct.
This article will help you debug and resolve this issue.
2. Environments
- Spring Boot 1.x or 2.x
- Java 1.8+
3. The problem code
3.1 pom.xml
The following is the pom.xml
content:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --></parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot-issue1</artifactId>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version></properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins></build>
3.2 Runner1.java and Runner2.java
There are two CommandLineRunner
implementations in this project:
@Componentpublic class Runner1 implements CommandLineRunner { private static Logger logger = LoggerFactory.getLogger(Runner1.class);
@Override public void run(String... strings) throws Exception { logger.debug("runner1 started"); }}
@Componentpublic class Runner2 implements CommandLineRunner { private static Logger logger = LoggerFactory.getLogger(Runner2.class);
@Override public void run(String... strings) throws Exception { logger.debug("runner2 started"); }}
Initially, everything works fine:
2019-03-08 11:21:17.395 DEBUG 91632 --- [ main] com.bswen.sbissue1.runners.Runner1 : runner1 started2019-03-08 11:21:17.395 DEBUG 91632 --- [ main] com.bswen.sbissue1.runners.Runner2 : runner2 started
However, after adding Runner3.java
, Runner1
and Runner2
stop working.
3.3 Adding Runner3.java to cause the problem
@Componentpublic class Runner3 implements Runnable { private static Logger logger = LoggerFactory.getLogger(Runner3.class); Object lock = new Object();
@Override @PostConstruct public void run() { logger.debug("runner3 started"); try { synchronized (lock) { lock.wait(); } logger.debug("runner3 unlocked"); }catch (Exception ex) { logger.error("",ex); } }}
In Runner3.java
, we set up a lock to block the current thread. The result is:
2019-03-08 11:23:48.206 DEBUG 91645 --- [ main] com.bswen.sbissue1.runners.Runner3 : runner3 started
The logs for Runner1
and Runner2
are not printed. Why?
3.4 The reason
The issue is caused by the @PostConstruct
annotation. Runner3
is a Runnable
, but it is not executed as a thread. Instead, it runs as a normal method, blocking the Spring Boot starter thread. As a result, Runner1
and Runner2
cannot execute.
3.5 How to resolve it
To fix the issue, remove the @PostConstruct
annotation and start Runner3
in a separate thread. Here’s the corrected code:
@Componentpublic class Runner3 implements Runnable { private static Logger logger = LoggerFactory.getLogger(Runner3.class); Object lock = new Object();
@Override public void run() { logger.debug("runner3 started"); try { synchronized (lock) { lock.wait(); } logger.debug("runner3 unlocked"); }catch (Exception ex) { logger.error("",ex); } }}
Start Runner3
in Runner2
:
@Componentpublic class Runner2 implements CommandLineRunner { private static Logger logger = LoggerFactory.getLogger(Runner2.class); @Autowired private Runner3 runner3;
@Override public void run(String... strings) throws Exception { logger.debug("runner2 started"); (new Thread(runner3)).start(); }}
Now, the logs show all runners working correctly:
2019-03-08 11:27:59.796 DEBUG 91655 --- [ main] com.bswen.sbissue1.runners.Runner1 : runner1 started2019-03-08 11:27:59.796 DEBUG 91655 --- [ main] com.bswen.sbissue1.runners.Runner2 : runner2 started2019-03-08 11:27:59.797 DEBUG 91655 --- [ Thread-3] com.bswen.sbissue1.runners.Runner3 : runner3 started
4. Summary
In this post, we explored why the CommandLineRunner
’s run
method might not be called in a Spring Boot application. The issue was caused by a blocking operation in a @PostConstruct
method, which prevented other runners from executing. By moving the blocking operation to a separate thread, we resolved the issue and ensured all runners worked as expected.
The example source code is available on GitHub.
Final Words + More Resources
My intention with this article was to help others who might be considering solving such a problem. So I hope that’s been the case here. If you still have any questions, don’t hesitate to ask me by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!