How does @ConditionalOnMissingBean let a user override an auto-configured bean? What ordering rules make this work reliably?
answer
- default = last resort, backs off
- user @Configuration processed BEFORE auto-config
- sees only already-processed definitions -> order sensitive
- matches on return type by default
- docs: only use on auto-config classes
basics
~10 sAuto-config beans are marked @ConditionalOnMissingBean, so they register only if the user hasn't defined one of that type. Because user @Configuration is processed before auto-configuration, a user bean wins and the default backs off.
solid answer
~40 s@ConditionalOnMissingBean registers the annotated bean only when no bean of that type (or matching name) already exists. Boot uses it pervasively so its defaults are 'last resort': DataSource, ObjectMapper, RestTemplateBuilder, etc. all back off if you declare your own. The mechanism depends on ordering — auto-configuration classes are imported via @AutoConfiguration/@ImportAutoConfiguration and are processed AFTER your regular @Configuration, and they're internally ordered with @AutoConfigureBefore/After/@AutoConfigureOrder. When the condition evaluates, your bean definition already exists, so OnMissingBean sees it and skips the default. Crucial gotcha: OnMissingBean only sees bean definitions that have already been processed — it is order-sensitive and works reliably for auto-config-vs-user code but is fragile between two beans in the same @Configuration or across auto-configs without explicit ordering.
code
java · 19 lines// --- Library auto-configuration (in a starter) ---
@AutoConfiguration
public class GreetingAutoConfiguration {
@Bean
@ConditionalOnMissingBean // default only if the app didn't define one
GreetingService greetingService() {
return new DefaultGreetingService();
}
}
// --- User application overrides it simply by declaring their own ---
@Configuration(proxyBeanMethods = false)
class MyConfig {
@Bean
GreetingService greetingService() { // processed BEFORE auto-config
return new CustomGreetingService(); // -> OnMissingBean backs off
}
}go deeper
Know it means 'register only if the user didn't provide one', enabling overrides.
Explain default matching on return type and the back-off concept.
Explain the ordering dependency (user config first, auto-config last) and its fragility.
Discuss @AutoConfigureBefore/After ordering, why the docs restrict it to auto-config, and using ConditionEvaluationReport to debug.
## The override contract `@ConditionalOnMissingBean` matches when **no bean matching the given criteria already exists** in the `BeanFactory`. Spring Boot puts it on almost every default bean so users can override by simply declaring their own — the default 'backs off'. This is the single most important reason Boot feels customizable without config files. ### Matching criteria By default it matches on the **return type** of the `@Bean` method. You can narrow/broaden it: - `value` / `type` — match by type(s). - `name` — match by bean name. - `annotation` — match beans carrying an annotation. - `ignored` / `ignoredType` — exclude certain types from the check. - `parameterizedContainer` — consider generic containers. ```java @Bean @ConditionalOnMissingBean // matches on ObjectMapper (the return type) ObjectMapper objectMapper() { ... } ``` ## Why ordering is everything `@ConditionalOnMissingBean` inspects only bean definitions **already known** when the condition runs. So the override works **because of processing order**: 1. **User `@Configuration` / component-scanned beans are processed first.** Regular configuration is registered before auto-configuration. 2. **Auto-configuration runs last.** Classes listed in `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports` are imported via `@EnableAutoConfiguration`/`AutoConfigurationImportSelector` and deliberately ordered to come after user config. 3. When `DataSourceAutoConfiguration`'s conditional bean evaluates, a user-declared `DataSource` (from a regular `@Configuration`) is already present ⇒ `OnMissingBean` fails ⇒ the default is skipped. ### Ordering *within* auto-configuration Across auto-config classes, order is controlled by `@AutoConfigureBefore`, `@AutoConfigureAfter`, and `@AutoConfigureOrder`. This matters when one auto-config's `OnMissingBean` must see beans from another. Getting this wrong is a classic source of 'sometimes my bean, sometimes the default' bugs. ## The order-sensitivity gotcha Because it's evaluated against **already-processed** definitions, `@ConditionalOnMissingBean`: - **Works** for auto-config-vs-user code (guaranteed order). - **Is fragile** between two `@Bean` methods in the **same** `@Configuration` (method processing order isn't a contract you should lean on). - **Is fragile** across two auto-configs without explicit `@AutoConfigureBefore/After`. - Reference docs explicitly warn: **use `@ConditionalOnMissingBean` / `@ConditionalOnBean` only on auto-configuration classes**, because they load in a well-defined order; in user config the order is far less predictable. ## Interaction with proxyBeanMethods Boot's auto-configs use `@Configuration(proxyBeanMethods = false)` for speed; this doesn't change OnMissingBean semantics but avoids CGLIB proxying of config methods. ## Diagnosing back-off Run with `--debug` (or `logging.level` for the report) to get the **ConditionEvaluationReport** ('Positive/Negative matches'), which shows exactly which `OnMissingBean` matched or backed off and why — the primary tool when an override doesn't take. ## When to use Use it in **your own starters/auto-config** so consumers can override your defaults. In plain application `@Configuration`, prefer just defining the bean you want, or use `@Primary`/explicit naming rather than relying on OnMissingBean ordering.
- Why does Spring recommend using @ConditionalOnMissingBean only inside auto-configuration classes and not ordinary @Configuration?Because it only sees bean definitions already processed when it evaluates. Auto-config classes load in a well-defined order (after user config, ordered by @AutoConfigureBefore/After), so the check is deterministic. In ordinary @Configuration the processing order of bean methods isn't a reliable contract, so the condition can match inconsistently.
- Your custom bean sometimes gets overridden by the default. How do you diagnose it?Enable the ConditionEvaluationReport (run with --debug or raise the autoconfigure logging level) to see positive/negative matches. Then check auto-config ordering (@AutoConfigureBefore/After) and whether your bean is declared in regular @Configuration so it's registered before the auto-config evaluates.
saying these in an interview costs you the question
- Claiming OnMissingBean scans the entire final context regardless of order
- Saying user beans are processed after auto-configuration
- Recommending OnMissingBean between two @Bean methods in the same user @Configuration as if order were guaranteed
- Confusing it with @Primary (which resolves ambiguity, not registration)