Mastering Spring Boot Startup: CommandLineRunner, ApplicationRunner, Listeners & More

This article explains the five ways Spring Boot can execute code during application startup—including CommandLineRunner, ApplicationRunner, ApplicationListener, @PostConstruct, and InitializingBean—detailing their usage, ordering, argument parsing, and best‑practice recommendations.

Programmer DD
Programmer DD
Programmer DD
Mastering Spring Boot Startup: CommandLineRunner, ApplicationRunner, Listeners & More

Introduction

Sometimes we need to execute code when the application starts, such as logging or certificate checks.

Spring Boot provides at least five ways to run code on startup; this article explains and compares them.

CommandLineRunner

CommandLineRunner

is an interface; implementing it runs code after the Spring application has started.

@Slf4j
@Component
@Order(2)
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        log.info("MyCommandLineRunner order is 2");
        if (args.length > 0) {
            for (int i = 0; i < args.length; i++) {
                log.info("MyCommandLineRunner current parameter is: {}", args[i]);
            }
        }
    }
}

When a CommandLineRunner bean is found, Spring calls its run() method and passes the command‑line arguments.

Build the jar with mvn clean package and run it with

java -jar springboot-application-startup-0.0.1-SNAPSHOT.jar --foo=bar --name=rgyb

. The result shows that arguments are not parsed:

Command‑line arguments are displayed as raw strings; they are not parsed. Use ApplicationRunner for parsing.

If the overridden run() method throws an exception, the application startup aborts.

The @Order annotation determines execution order among multiple runners (lower numbers run first).

⚠️ Do not overuse @Order Excessive ordering indicates hidden dependencies; prefer reducing such coupling.

Summary

If you only need simple space‑separated arguments, MyCommandLineRunner is sufficient.

ApplicationRunner

To parse command‑line options, implement ApplicationRunner. The ApplicationArguments object provides getOptionValues returning a list of values.

@Component
@Slf4j
@Order(1)
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("MyApplicationRunner order is 1");
        log.info("MyApplicationRunner Current parameter is {}:", args.getOptionValues("foo"));
    }
}

Running the jar with

java -jar springboot-application-startup-0.0.1-SNAPSHOT.jar --foo=bar,rgyb

shows parsed values:

ApplicationRunner

can access ApplicationArguments and retrieve option values as lists.

Exceptions thrown in run() also abort startup. @Order works for ApplicationRunner and shares ordering with CommandLineRunner.

ApplicationListener

If no command‑line parsing is needed, bind startup logic to ApplicationReadyEvent via an ApplicationListener.

@Slf4j
@Component
@Order(0)
public class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        log.info("MyApplicationListener is started up");
    }
}

The listener runs after all previous startup solutions have completed:

ApplicationReadyEvent

fires only when the application is fully ready, after other startup mechanisms. @Order can order listeners, but this ordering is independent of runners.

Summary

Use ApplicationListener<ApplicationReadyEvent> for global startup logic without needing command‑line arguments.

@PostConstruct

Another simple way is to annotate a bean method with @PostConstruct, which runs after bean creation but before the container is fully started.

@Component
@Slf4j
@DependsOn("myApplicationListener")
public class MyPostConstructBean {
    @PostConstruct
    public void testPostConstruct() {
        log.info("MyPostConstructBean");
    }
}

Result shows it runs before the application is ready; ordering with @Order is not reliable because dependencies may be injected later.

Methods annotated with @PostConstruct execute after bean creation and cannot be ordered with @Order.

Use @DependsOn to create explicit dependencies, though it is also discouraged.

Summary

@PostConstruct

should be used for initialization of a single bean.

InitializingBean

Implementing InitializingBean and overriding afterPropertiesSet() provides similar behavior to @PostConstruct, but the method is called after all bean properties have been set.

@Component
@Slf4j
public class MyInitializingBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("MyInitializingBean.afterPropertiesSet()");
    }
}

Result shows it runs after property injection, making it safer when the initialization logic depends on @Autowired fields.

⚠️ Difference between @PostConstruct and afterPropertiesSet afterPropertiesSet runs after property injection; @PostConstruct may run before. Therefore afterPropertiesSet avoids NullPointerExceptions caused by missing injections.

Summary

When using constructor injection, both approaches are equivalent.

Source Code Analysis

In SpringApplication.java the callRunners method collects ApplicationRunner and CommandLineRunner beans, sorts them with AnnotationAwareOrderComparator, and invokes each.

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    // get ApplicationRunner beans
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    // get CommandLineRunner beans
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    // sort both types together
    AnnotationAwareOrderComparator.sort(runners);
    // invoke each runner
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}

Reviewing the full SpringApplication source reveals the entire startup process.

Conclusion

A diagram (omitted here) summarizes the relationships among the different startup mechanisms.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring BootApplicationListenerApplicationRunnerCommandLineRunnerapplication startup
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.