Walk through what happens when refresh() is called on an ApplicationContext.
answer
- prepare → obtainFactory → prepareFactory → invoke BFPP → register BPP
- messageSource → multicaster → onRefresh → listeners
- finishBeanFactoryInit = preInstantiateSingletons (eager)
- finishRefresh = start Lifecycle + ContextRefreshedEvent
- failure → destroyBeans + cancelRefresh
basics
~10 srefresh() is the startup routine: it prepares and loads the bean factory, applies configuration post-processors, registers post-processors, sets up the message source, event multicaster, and listeners, eagerly creates all non-lazy singletons, then publishes ContextRefreshedEvent.
solid answer
~30 srefresh() (in AbstractApplicationContext) drives the whole container startup as an ordered, synchronized sequence: prepareRefresh (mark active, init property sources), obtainFreshBeanFactory (load/create the DefaultListableBeanFactory and its bean definitions), prepareBeanFactory (register standard beans/resolvers), invokeBeanFactoryPostProcessors (this is where @Configuration classes are parsed by ConfigurationClassPostProcessor and definitions can be added/modified), registerBeanPostProcessors, initMessageSource, initApplicationEventMulticaster, onRefresh (subclass hook — Boot starts the embedded web server here), registerListeners, finishBeanFactoryInitialization (preInstantiateSingletons — eagerly builds all non-lazy singletons), and finishRefresh (start Lifecycle beans, publish ContextRefreshedEvent). If any step throws, it destroys already-created singletons and resets the active flag before rethrowing.
code
java · 10 lines// A ContextRefreshedEvent listener runs after finishRefresh() — all
// singletons exist and Lifecycle beans have started.
@Component
class ReadyLogger {
@EventListener
void onReady(ContextRefreshedEvent e) {
// safe: every non-lazy singleton is fully initialized here
System.out.println("context ready: " + e.getApplicationContext().getId());
}
}go deeper
Know that refresh() is the startup that builds all beans and that ContextRefreshedEvent signals completion.
List the major phases in order and identify that non-lazy singletons are pre-instantiated near the end.
Reproduce the full ordered sequence, explain why BFPPs precede singleton creation, and describe failure cleanup.
Reason about extension points (onRefresh for web servers, ordering of post-processors), refresh-once vs refreshable semantics, and how this pipeline underpins Boot startup and graceful shutdown.
`refresh()` is defined on `AbstractApplicationContext` and is `synchronized` on a startup monitor. It runs this fixed sequence — memorize the ordering, it explains most 'why did my bean init in that order' questions: 1. **prepareRefresh()** — record start time, set the `active` flag, initialize property sources (`initPropertySources()`), and validate required properties (`Environment.validateRequiredProperties`). 2. **obtainFreshBeanFactory()** — get the `ConfigurableListableBeanFactory`. For `AbstractRefreshableApplicationContext` (e.g. `ClassPathXmlApplicationContext`) this *destroys any prior factory, creates a fresh `DefaultListableBeanFactory`, and loads bean definitions* (parses XML / scans). For `GenericApplicationContext` it just returns the already-populated factory and flips a one-time `refreshed` guard. 3. **prepareBeanFactory()** — configure the factory: set the bean classloader, register the SpEL expression resolver and a `ResourceEditorRegistrar`, add `ApplicationContextAwareProcessor`, ignore certain aware interfaces for autowiring, and register resolvable dependencies (`BeanFactory`, `ApplicationContext`, `Environment`, etc.) plus default environment beans. 4. **postProcessBeanFactory()** — empty subclass hook. 5. **invokeBeanFactoryPostProcessors()** — instantiate and invoke all `BeanFactoryPostProcessor`s in order (`PriorityOrdered` → `Ordered` → rest). Crucially this includes `ConfigurationClassPostProcessor`, which parses `@Configuration`/`@Bean`/`@ComponentScan` and *registers the resulting bean definitions*. After this step the full set of bean definitions is known. (BFPP mechanics themselves are a sibling topic.) 6. **registerBeanPostProcessors()** — instantiate and *register* (not yet invoke) all `BeanPostProcessor`s so they can wrap beans created later. 7. **initMessageSource()** — set up i18n `MessageSource` (falls back to a delegating default if none defined). 8. **initApplicationEventMulticaster()** — create the `ApplicationEventMulticaster` used to dispatch events. 9. **onRefresh()** — subclass hook. In Spring Boot's web contexts this is where the *embedded Tomcat/Netty server is created* (though it starts accepting requests in finishRefresh). 10. **registerListeners()** — register statically declared `ApplicationListener`s and any listener beans; earlier-published early events are flushed now. 11. **finishBeanFactoryInitialization()** — freeze the configuration and call `beanFactory.preInstantiateSingletons()`, which **eagerly instantiates every non-lazy singleton** (this is when most of your `@Component`/`@Bean` objects are actually created and wired). Beans marked `@Lazy` are skipped until first use. 12. **finishRefresh()** — clear resource caches, initialize the `LifecycleProcessor`, call `getLifecycleProcessor().onRefresh()` (which **starts `SmartLifecycle` beans with `isAutoStartup()`** — phased start belongs to the lifecycle sibling topic), and publish `ContextRefreshedEvent`. **Failure handling.** The whole body is wrapped in try/catch: on exception it logs, calls `destroyBeans()` to run destroy callbacks on already-created singletons, sets `active=false` via `cancelRefresh()`, and rethrows. A partially built context is thus torn down cleanly. **close() is the mirror image** — `doClose()` publishes `ContextClosedEvent`, stops `Lifecycle` beans, calls `destroySingletons()` (running `@PreDestroy`/`DisposableBean`), and closes the bean factory. `registerShutdownHook()` wires that to JVM shutdown. **Gotchas:** (a) because non-lazy singletons are created in step 11, a broken bean fails startup *fast* — that's intentional. (b) `ContextRefreshedEvent` fires at the very end, so it's the safe place to run code that needs all beans ready. (c) Anything that adds/modifies bean definitions must run as a BeanFactoryPostProcessor (step 5) — after step 11 the definitions are frozen.
- At which phase are your @Component singletons actually instantiated?In finishBeanFactoryInitialization(), via beanFactory.preInstantiateSingletons() — the second-to-last step. Non-lazy singletons are created eagerly there; @Lazy ones are deferred.
- Why must a BeanFactoryPostProcessor run before finishBeanFactoryInitialization?BFPPs (step 5) are the only place bean *definitions* can be added or mutated. After preInstantiateSingletons the definitions are frozen and singletons are being built, so definition changes would be too late.
- What does refresh() do if a singleton fails to construct?The refresh body catches the exception, calls destroyBeans() to run destroy callbacks on already-created singletons, cancels the refresh (active=false), and rethrows — so you don't get a half-started container.
saying these in an interview costs you the question
- Saying singletons are created lazily on first getBean by default (they're eagerly created during refresh)
- Placing embedded-server startup or ContextRefreshedEvent at the wrong end of the sequence
- Claiming you can add bean definitions after refresh completes
- Confusing invokeBeanFactoryPostProcessors (definitions) with registerBeanPostProcessors (bean wrapping)