Why CommandLineRunner Can Halt Your Spring Boot Startup—and How to Fix It
This article explains the differences between Spring Boot’s CommandLineRunner and ApplicationRunner, illustrates common pitfalls when using CommandLineRunner—such as blocking startup and causing exceptions—and shows how to run tasks in a separate thread to avoid startup failures.
Usage Scenarios
During application development you often need to perform certain operations when the container starts. Spring Boot provides two interfaces, CommandLineRunner and ApplicationRunner, to meet this requirement.
Differences Between the Two Interfaces
The only real difference is the method signature: CommandLineRunner.run(String... args) receives a simple string array, while ApplicationRunner.run(ApplicationArguments args) receives an ApplicationArguments object. Choose the one that best fits your needs.
Special Scenarios
Sometimes the startup task is not a one‑off operation; it may involve looping database queries, processing messages from a queue, or other continuous work.
Common Pitfall
When a CommandLineRunner contains a long‑running loop that throws an exception, the exception propagates to the main thread, causing the entire Spring Boot application to fail to start. The logs show that the startup time is never printed because the runner blocks the completion of the startup process.
@Component
public class RunService implements CommandLineRunner {
@Override
public void run(String... args) {
int i = 0;
while (true) {
i++;
try {
Thread.sleep(10000);
System.out.println("过去了10秒钟……,i的值为:" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 4) {
// 第40秒时抛出一个异常
throw new RuntimeException();
}
continue;
}
}
}The above code causes the application to abort with an IllegalStateException: Failed to execute CommandLineRunner after the fourth iteration.
Solution: Run Tasks in a Separate Thread
To prevent the runner from blocking the main startup flow, start a new thread inside the run method and perform the long‑running work there. Exceptions in this thread no longer affect the main application lifecycle.
@Component
public class RunService implements CommandLineRunner {
@Override
public void run(String... args) {
new Thread() {
@Override
public void run() {
int i = 0;
while (true) {
i++;
try {
Thread.sleep(10000);
System.out.println("过去了10秒钟……,i的值为:" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 4) {
// 第40秒时抛出一个异常
throw new RuntimeException();
}
continue;
}
}
}.start();
}
}With this approach the application starts successfully, prints the startup time, and the exception is logged only in the separate thread, leaving the main process unaffected.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
