Why do @Bean methods in an auto-configuration almost always use @ConditionalOnMissingBean, and how do the conditional guards let a library back off?
answer
- OnMissingBean = back off, user wins
- auto-config runs after user config → condition sees user beans
- OnClass = ASM bytecode check, no class loading
- OnProperty matchIfMissing for on-by-default
- OnBean is order-sensitive
basics
~20 s@ConditionalOnMissingBean means 'only create this bean if the application hasn't already defined one.' It lets the library provide a sensible default while letting the app override it just by declaring its own bean of that type.
solid answer
~40 sAuto-configuration should provide defaults, not force them. @ConditionalOnMissingBean makes a @Bean method contribute only when no bean of that type already exists in the context — so if the application declares its own, the auto-config silently 'backs off' and the user's bean wins. This works because auto-configuration is processed *after* user configuration, so by the time the condition is evaluated the user's beans are already registered. Other guards shape activation similarly: @ConditionalOnClass activates only if a class is on the classpath (so optional integrations don't blow up when the dependency is absent), @ConditionalOnProperty gates on config flags, and @ConditionalOnBean requires a prerequisite bean. Together these make a starter self-adjusting: it wires things up when it makes sense and stays out of the way otherwise, which is the whole point of 'convention over configuration.'
code
java · 14 lines@AutoConfiguration
@ConditionalOnClass(GreetingService.class) // only if the type is on the classpath
public class GreetingAutoConfiguration {
@Bean
@ConditionalOnMissingBean // back off if the app already defines one
@ConditionalOnProperty(prefix = "acme.greeting",
name = "enabled",
havingValue = "true",
matchIfMissing = true) // on by default
public GreetingService greetingService() {
return new GreetingService("Hello");
}
}go deeper
Know that @ConditionalOnMissingBean lets the app override the library's default bean.
Must explain the ordering (auto-config after user config) that makes back-off correct, and name @ConditionalOnClass/@ConditionalOnProperty.
Explains ASM-based class checking, order-sensitivity of @ConditionalOnBean, and matchIfMissing semantics.
Reasons about starter interactions, custom Condition implementations, and how return-type inference affects matching.
**The problem conditions solve.** A library's auto-configuration must be *polite*: it should supply defaults but never clobber what the application (or another library) already provides, and never fail just because an optional dependency is missing. Spring Boot's `@Conditional*` family enforces this. **@ConditionalOnMissingBean — the back-off workhorse.** Placed on a `@Bean` method (or class), it means 'register this bean only if the context has no bean matching this type (or name).' Example: your starter defines a default `ObjectMapper`, but if the app already declared one, yours is skipped. This is the mechanism behind 'the app can always override a default.' **Why ordering makes it work.** Auto-configuration classes are registered *after* the application's own `@Configuration`/`@Component` classes. So when `@ConditionalOnMissingBean` is evaluated, user beans already exist in the `BeanDefinitionRegistry`. If auto-config ran first, the condition couldn't see the user's bean and back-off would fail. This is also why you should *not* put `@ConditionalOnMissingBean` on user-facing config — it's designed for the auto-config phase. **@ConditionalOnClass — guard optional dependencies.** Activates the config/bean only if the named class is present on the classpath. Crucially, Spring Boot evaluates this by reading bytecode (ASM) *without loading/initializing* the class, so referencing a type that isn't present doesn't throw `NoClassDefFoundError`. Best practice: annotate at the *class* level and only reference the optional type in method return types/parameters, so the condition filters the whole config before any method is touched. The inverse is `@ConditionalOnMissingClass`. **@ConditionalOnProperty — feature flags.** Activates based on a property, e.g. `@ConditionalOnProperty(prefix = "acme.greeting", name = "enabled", havingValue = "true", matchExistingValue... )`. `matchIfMissing = true` makes the feature on-by-default. Great for letting users disable a starter. **@ConditionalOnBean / @ConditionalOnMissingBean caveat.** `@ConditionalOnBean` depends on *what has been processed so far*, so it is order-sensitive and mainly reliable inside auto-configuration (where ordering is controlled via `@AutoConfigureAfter`). Don't rely on it in regular user config. **Other common guards.** `@ConditionalOnWebApplication` / `@ConditionalOnNotWebApplication`, `@ConditionalOnResource`, `@ConditionalOnExpression` (SpEL). You can also write a custom `Condition` implementing `org.springframework.context.annotation.Condition` and reference it with `@Conditional`. **Gotchas.** - `@ConditionalOnMissingBean` without arguments infers the type from the method return type — a too-broad or too-narrow return type changes what it matches. Prefer explicit types when the return type is a superclass. - Two starters both using `@ConditionalOnMissingBean` for the same type can race; ordering hints resolve who provides the default. - Conditions are evaluated once at context build time, not re-evaluated later. **When to use which.** Optional third-party integration → `@ConditionalOnClass`. User-overridable default → `@ConditionalOnMissingBean`. Toggle → `@ConditionalOnProperty`. Depends on another auto-configured bean → `@ConditionalOnBean` + `@AutoConfigureAfter`.
- Why must auto-configuration be processed after user configuration for @ConditionalOnMissingBean to work?The condition checks whether a matching bean already exists. If auto-config ran first, the user's bean wouldn't be registered yet, so the condition would falsely pass and the auto-config bean would win — defeating overridability. Running last lets it see and defer to user beans.
- How does @ConditionalOnClass avoid a NoClassDefFoundError when the class is absent?Spring Boot inspects the annotation's referenced types via ASM bytecode reading rather than actually loading the class. The condition fails cleanly if the class isn't present, and because it's typically at class level, no method referencing that type is ever invoked.
saying these in an interview costs you the question
- Saying @ConditionalOnMissingBean re-evaluates at runtime
- Thinking @ConditionalOnClass loads the class (would risk NoClassDefFoundError)
- Claiming @ConditionalOnBean is reliable in ordinary user @Configuration
- Assuming auto-config runs before user config