skip to content

Application events & listeners

Boot fires events across startup — starting, environment prepared, ready, failed — some of them before the context and its listeners even exist. ApplicationReadyEvent versus @PostConstruct is the practical distinction that gets asked.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is ApplicationReadyEvent in Spring Boot and when should you run code on it?

level: juniorimportance: must knowfreq 62%

answer

  1. last successful-startup event
  2. after refresh AND after runners
  3. web server already accepting traffic
  4. @EventListener works (context exists)
  5. not published on failure

basics

~20 s

ApplicationReadyEvent fires when the application has fully started — the context is refreshed and all runners have finished — so it is safe to say the app is ready to serve requests. Use it for startup work that needs a fully live app.

solid answer

~40 s

ApplicationReadyEvent is published by SpringApplication as the last step of startup, after the ApplicationContext is refreshed and after every CommandLineRunner and ApplicationRunner has completed. At that point all beans exist and the web server is accepting connections, so it is the safe place for 'app is live' side effects: warming caches, kicking off background schedulers, emitting a 'started' metric, or notifying an external system. You listen with a normal @EventListener or an ApplicationListener bean because the context already exists. Contrast it with ContextRefreshedEvent (fires earlier, before runners and before the servlet container is guaranteed ready) and ApplicationStartedEvent (after refresh but before runners). If startup fails, ApplicationReadyEvent is never published; ApplicationFailedEvent is published instead.

code

java · 14 lines
java
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
class StartupTasks {

    @EventListener(ApplicationReadyEvent.class)
    void warmCachesAndAnnounce(ApplicationReadyEvent event) {
        long ms = event.getTimeTaken().toMillis(); // startup duration
        // context fully refreshed, runners done, server accepting traffic
        // -> safe to warm caches / start schedulers / emit 'started' metric
    }
}

go deeper

for a junior

Know it means 'app fully started, safe to do startup side effects' and that a plain @EventListener bean works.

for a middle

Distinguish Ready vs Started vs ContextRefreshed and know it's skipped on failure.

for a senior

Discuss ordering relative to runners, AvailabilityChangeEvent/readiness probes, and the risk of blocking work here.

for a principal

Reason about readiness-probe gating, thread of execution, and using it as a system 'live' boundary vs. availability state transitions.

## What it is `ApplicationReadyEvent` is a Spring Boot application-lifecycle event (class `org.springframework.boot.context.event.ApplicationReadyEvent`) published by `SpringApplication.run(...)` at the very end of a successful startup. 'Published' means Spring's event mechanism broadcasts an object to interested listeners. ## Exactly when it fires Startup proceeds through an ordered sequence. `ApplicationReadyEvent` is published **after**: 1. The `ApplicationContext` (the Spring container holding all beans) has been *refreshed* — every singleton bean is created and initialized. 2. `ApplicationStartedEvent` has been published. 3. **All** `CommandLineRunner` and `ApplicationRunner` beans have run to completion. So when it fires, the application is fully wired and, for a web app, the embedded server (Tomcat/Netty) is up and accepting traffic. This makes it the canonical 'the app is now live' hook. ## How to listen Because the context already exists, you use ordinary listener mechanisms: ```java @Component class ReadyHandler { @EventListener(ApplicationReadyEvent.class) void onReady(ApplicationReadyEvent e) { /* ... */ } } ``` or implement `ApplicationListener<ApplicationReadyEvent>`. Both work here — unlike the *early* events (ApplicationStartingEvent, ApplicationEnvironmentPreparedEvent) which fire before any bean exists. ## When to use it - Warm caches or connection pools once everything is available. - Start long-running background tasks/schedulers that should not run mid-startup. - Publish a 'started' health/metric signal or notify a discovery service. - Trigger a one-time job that needs the full context and a listening web server. ## Gotchas / edge cases - **Do not** put slow blocking work here if you also gate readiness probes on it — you delay traffic acceptance. Boot separately publishes an `AvailabilityChangeEvent(ReadinessState.ACCEPTING_TRAFFIC)` right after readiness. - If startup throws, this event is **never** published; you get `ApplicationFailedEvent` instead. Don't rely on ReadyEvent for cleanup that must always run. - Listeners run on the main startup thread, so an exception thrown in a ReadyEvent listener can fail the boot process. - It is distinct from `ContextRefreshedEvent`, which fires earlier (on every refresh, and before runners); prefer ReadyEvent when you truly mean 'the whole application finished starting'. ## Related events `ApplicationStartedEvent` (post-refresh, pre-runners) vs `ApplicationReadyEvent` (post-runners). If you need to act before user code runners, use Started; to act after everything, use Ready.

  • What is the difference between ApplicationReadyEvent and ApplicationStartedEvent?
    ApplicationStartedEvent fires right after the context is refreshed but BEFORE any CommandLineRunner/ApplicationRunner runs. ApplicationReadyEvent fires AFTER all those runners complete — it is the true 'fully started' signal.
  • Why might you prefer ApplicationReadyEvent over ContextRefreshedEvent?
    ContextRefreshedEvent fires on every context refresh and before runners, and doesn't guarantee the app finished its full boot sequence. ApplicationReadyEvent fires once, after runners, when the app is genuinely live.

saying these in an interview costs you the question

  • Saying ApplicationReadyEvent fires before the runners
  • Claiming it's published even when startup fails
  • Confusing it with ContextRefreshedEvent as identical
  • Thinking you must register it via spring.factories (it's a normal bean listener)

context

open as a page

Why can't a @Component @EventListener catch ApplicationStartingEvent or ApplicationEnvironmentPreparedEvent, and how do you listen to those early events?

level: seniorimportance: must knowfreq 40%

basics

~10 s

Those events fire before the ApplicationContext and its beans exist, so a bean-based @EventListener isn't registered yet. You must register an ApplicationListener before the context is built — via SpringApplication.addListeners(), SpringApplicationBuilder.listeners(), or META-INF/spring.factories.

open as a page

Walk through the ordered sequence of Spring Boot application lifecycle events during startup.

level: middleimportance: should knowfreq 45%

basics

~10 s

Roughly: ApplicationStartingEvent, then ApplicationEnvironmentPreparedEvent, then ApplicationContextInitializedEvent, then ApplicationPreparedEvent (context refreshes here), then ApplicationStartedEvent, then ApplicationReadyEvent. On error, ApplicationFailedEvent fires instead.

open as a page

What is SpringApplicationRunListener, how is it registered, and how does it relate to the lifecycle events?

level: seniorimportance: should knowfreq 28%

basics

~10 s

SpringApplicationRunListener is the low-level hook Spring Boot calls during the run sequence (starting, environmentPrepared, contextPrepared, contextLoaded, started, ready, failed). Boot's built-in one publishes the lifecycle events. You register custom ones via META-INF/spring.factories.

open as a page

How does ApplicationFailedEvent work, and how would you use it (and the early listeners) to build robust startup diagnostics?

level: principalimportance: nice to knowfreq 20%

basics

~20 s

ApplicationFailedEvent is published when startup throws, carrying the exception and (if it got that far) the context. Because failures can occur before the context exists, listen with an early ApplicationListener registered outside the context so you can log/alert reliably.

open as a page