skip to content

What is SmartInitializingSingleton.afterSingletonsInstantiated(), and how does it differ from SmartLifecycle start()?

level: seniorimportance: should knowfreq 34%

answer

  1. fires after ALL eager singletons instantiated
  2. preInstantiateSingletons() second pass
  3. one-shot, no stop pair, before start()
  4. EventListenerMethodProcessor uses it
  5. lazy/prototype beans don't trigger it

basics

~20 s

afterSingletonsInstantiated() is a one-time callback fired after ALL non-lazy singletons are created, so a bean can safely act on the whole set of singletons. It runs during singleton pre-instantiation, before SmartLifecycle start(), which comes later at finishRefresh().

solid answer

~40 s

SmartInitializingSingleton is a single-method interface; afterSingletonsInstantiated() is invoked by DefaultListableBeanFactory.preInstantiateSingletons() after every non-lazy singleton has been instantiated and initialized. It's the hook for logic that needs the complete singleton set — e.g. scanning all beans of a type and registering them. Each implementing singleton gets the callback once. It differs from SmartLifecycle.start() in timing and purpose: afterSingletonsInstantiated() fires during finishBeanFactoryInitialization, still inside refresh, before the LifecycleProcessor runs; SmartLifecycle.start() fires later in finishRefresh() and represents starting ongoing activity that is also stopped on close. Use SmartInitializingSingleton for one-shot cross-bean wiring/validation after construction; use SmartLifecycle for start/stop of runtime processes. Note it only fires for eagerly instantiated singletons — lazy or prototype beans don't trigger it.

code

java · 17 lines
java
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Component;

@Component
class HandlerRegistry implements SmartInitializingSingleton {
    private final ObjectProvider<MessageHandler> handlers;
    HandlerRegistry(ObjectProvider<MessageHandler> handlers) { this.handlers = handlers; }

    // Runs once, after every eager singleton (incl. all MessageHandlers) exists.
    @Override public void afterSingletonsInstantiated() {
        handlers.orderedStream().forEach(h -> register(h.type(), h));
    }
    private void register(String type, MessageHandler h) { /* ... */ }
}

interface MessageHandler { String type(); }

go deeper

for a junior

Know it's a callback after all singletons are created.

for a middle

Should contrast it with @PostConstruct (whole set vs single bean).

for a senior

Should place it in preInstantiateSingletons() and order it before SmartLifecycle.start(); cite EventListenerMethodProcessor.

for a principal

Distinguishes one-shot cross-bean wiring from phased runtime lifecycle and chooses between it, ContextRefreshedEvent, and ApplicationRunner deliberately.

## The gap it fills `@PostConstruct` runs when *one* bean finishes initializing, but at that moment other singletons may not exist yet. Sometimes you need to act **after the entire set of eager singletons is ready** — for example, collect every bean implementing some interface, build a registry, or cross-validate configuration. That's **`org.springframework.beans.factory.SmartInitializingSingleton`**, a single-method interface: ```java void afterSingletonsInstantiated(); ``` ## When it fires `DefaultListableBeanFactory.preInstantiateSingletons()` (called from `AbstractApplicationContext.finishBeanFactoryInitialization()` during `refresh()`) does two passes: 1. Instantiate all non-lazy singletons (running their `@PostConstruct`/`InitializingBean` callbacks). 2. Iterate again; for each singleton that implements `SmartInitializingSingleton`, call **`afterSingletonsInstantiated()`** once. So by the time your callback runs, **every eager singleton already exists and is fully initialized** — you can safely look them up (e.g. via the `ApplicationContext` or `ObjectProvider`). ## How it differs from SmartLifecycle.start() | Aspect | SmartInitializingSingleton.afterSingletonsInstantiated() | SmartLifecycle.start() | |---|---|---| | Purpose | One-shot post-construction wiring/validation across all singletons | Start ongoing activity (threads, servers, listeners) | | Timing in refresh() | During `finishBeanFactoryInitialization()` (singleton pre-instantiation) | Later, in `finishRefresh()` via the LifecycleProcessor | | Paired stop? | No | Yes — `stop()` on close | | Repeatable? | No, fires once | Yes — can be stopped and started again | | Ordering control | No phases | Phased via getPhase() | Crucially, **afterSingletonsInstantiated() runs strictly before any SmartLifecycle.start()**, because singleton instantiation completes before `finishRefresh()`. So a SmartInitializingSingleton can prepare state that the subsequently-started lifecycle beans rely on. ## Where Spring itself uses it Framework infrastructure uses it heavily: `EventListenerMethodProcessor` (which turns `@EventListener` methods into `ApplicationListener`s) implements `SmartInitializingSingleton` so it can scan *all* beans for annotated methods after they all exist. Scheduling and validation processors use similar post-instantiation scans. ## Gotchas - **Only eager singletons trigger it.** `@Lazy` singletons and prototype beans never receive the callback (they aren't part of pre-instantiation). - **It's not a lifecycle stop pair** — there's no matching "before destruction" method; use `@PreDestroy`/`DisposableBean` for teardown. - **Don't do long-running/blocking work here** — it runs on the bootstrap thread and delays context startup; for anything ongoing, use SmartLifecycle instead. - **Runs during refresh, before ContextRefreshedEvent** — if you specifically want a signal after the context is fully refreshed and lifecycle-started, listen for `ContextRefreshedEvent` or use `ApplicationRunner`/`CommandLineRunner` (Boot) instead.

  • Does afterSingletonsInstantiated() fire for lazy or prototype beans?
    No. It's invoked during eager singleton pre-instantiation, so only non-lazy singletons implementing SmartInitializingSingleton receive it; lazy singletons and prototypes never do.
  • Which runs first: afterSingletonsInstantiated() or SmartLifecycle.start()?
    afterSingletonsInstantiated() — it runs during finishBeanFactoryInitialization(), whereas lifecycle start() runs later in finishRefresh() via the LifecycleProcessor.

context