Master SpringBoot Runners: ApplicationRunner vs CommandLineRunner Explained
This guide explains how to run custom code after SpringApplication starts by implementing ApplicationRunner or CommandLineRunner, compares their method signatures and argument handling, shows execution timing, provides practical examples, and demonstrates how to control execution order with @Order or Ordered.
Environment: SpringBoot 3.3.0
1. Introduction
If you need to execute specific code after SpringApplication starts, implement the ApplicationRunner or CommandLineRunner interface. Both provide a run method that is invoked before SpringApplication.run(...) completes.
2. Differences Between the Two
ApplicationRunner method signature
<code>void run(ApplicationArguments args) throws Exception;</code>CommandLineRunner method signature
<code>void run(String... args) throws Exception;</code>The only difference is the parameter type. Below are example usages.
First, add startup parameters, e.g.:
<code>--pack.title=xxxooo --pack.version=1.0.1</code>ApplicationRunner example
<code>public void run(ApplicationArguments args) throws Exception {
System.out.printf("AR Args: %s%n", Arrays.toString(args.getSourceArgs()));
System.out.printf("AR 参数名: %s%n", args.getOptionNames());
}</code>Output:
CommandLineRunner example
<code>public void run(String... args) throws Exception {
System.err.printf("CLR Args: %s%n", Arrays.toString(args));
}</code>Output:
Compared to CommandLineRunner, ApplicationRunner provides richer argument handling, including access to original arguments and option names via getOptionNames() and getOptionValues() .
3. Execution Timing
When SpringApplication#run is called, the core method eventually invokes the runners:
<code>public class SpringApplication {
public ConfigurableApplicationContext run(String... args) {
// ...
try {
prepareContext(...);
refreshContext(context);
afterRefresh(context, applicationArguments);
// ...
// Call ApplicationRunner and CommandLineRunner
callRunners(context, applicationArguments);
}
// ...
return context;
}
}</code>The runners are invoked in the following order:
<code>private void callRunner(Runner runner, ApplicationArguments args) {
if (runner instanceof ApplicationRunner) {
callRunner(ApplicationRunner.class, runner, applicationRunner -> applicationRunner.run(args));
}
if (runner instanceof CommandLineRunner) {
callRunner(CommandLineRunner.class, runner, commandLineRunner -> commandLineRunner.run(args.getSourceArgs()));
}
}</code>Thus, ApplicationRunner runs first .
4. Practical Examples
Example 1 – Schedule a Task After Startup
<code>@Component
public class TaskSchedulerInitializer implements ApplicationRunner {
private final TaskScheduler taskScheduler;
public TaskSchedulerInitializer(TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
@Override
public void run(ApplicationArguments args) throws Exception {
taskScheduler.schedule(this::task, new CronTrigger("0/5 * * * * ?"));
}
private void task() {
System.out.println("执行任务...");
}
}</code>Note: You need to configure a TaskScheduler bean.
Example 2 – Warm Up Cache After Container Starts
<code>@Component
public class CacheDataWarmup implements ApplicationRunner {
private final CacheManager cacheManager;
private final SysDictService dictService;
public CacheDataWarmup(CacheManager cacheManager, SysDictService dictService) {
this.cacheManager = cacheManager;
this.dictService = dictService;
}
@Override
public void run(ApplicationArguments args) throws Exception {
List<SysDict> dicts = this.dictService.queryAll();
this.cacheManager.getCache("dicts").put("allparams", dicts);
}
}</code>Ensure the cache starter is on the classpath, or implement your own cache.
Example 3 – Load External Resource Files
<code>@Component
public class LoadOuterResource implements ApplicationRunner {
private final ConfigurableEnvironment environment;
public LoadOuterResource(ConfigurableEnvironment environment) {
this.environment = environment;
}
@Override
public void run(ApplicationArguments args) throws Exception {
YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
try {
List<PropertySource<?>> list = sourceLoader.load("pack", new ClassPathResource("com/pack/binder/properties/pack.yml"));
list.forEach(propertySource -> environment.getPropertySources().addLast(propertySource));
} catch (IOException e) {
e.printStackTrace();
}
}
}</code>These examples demonstrate various tasks you can perform with runners.
5. Controlling Execution Order
If multiple runners exist and a specific order is required, implement org.springframework.core.Ordered or use the @Order annotation.
<code>@Component
@Order(2)
public class FirstRunner implements ApplicationRunner {
// ...
}
@Component
@Order(1)
public class SecondRunner implements ApplicationRunner {
// ...
}</code>Execution will be: SecondRunner → FirstRunner .
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
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.