Conditional Beans (@ConditionalOn*)
Intermediate@ConditionalOnClass, @ConditionalOnProperty, and friends let you register beans only when specific conditions on the classpath or environment hold true.
Overview
Conditional annotations are the foundation of Spring Boot's auto-configuration system. They let you make bean registration dependent on runtime conditions — the presence of a class on the classpath, a property value, a missing bean, or a custom match expression. This is how `spring-boot-starter-web` auto-configures a DispatcherServlet only when the right classes are available, and how you write your own starter libraries. The most common annotations are `@ConditionalOnClass`, `@ConditionalOnMissingBean`, `@ConditionalOnProperty`, and `@ConditionalOnExpression`. Under the hood every `@ConditionalOn*` annotation is a specialisation of `@Conditional(SomeCondition.class)`.
Common @ConditionalOn* Annotations
`@ConditionalOnClass` registers the bean only when a given class is present on the classpath — the typical guard in auto-configuration. `@ConditionalOnMissingBean` is the override hook: register a default bean only if the user has not already defined one. `@ConditionalOnProperty` gates on a property value.
@Configuration
@ConditionalOnClass(DataSource.class) // only if JDBC is on classpath
public class DataSourceAutoConfig {
@Bean
@ConditionalOnMissingBean(DataSource.class) // default — user can override
public DataSource defaultDataSource(DataSourceProperties props) {
return DataSourceBuilder.create()
.url(props.getUrl())
.username(props.getUsername())
.password(props.getPassword())
.build();
}
}
@Bean
@ConditionalOnProperty(
name = "feature.cache.enabled",
havingValue = "true",
matchIfMissing = false // don't create bean if property absent
)
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("users");
}@ConditionalOnExpression and @ConditionalOnWebApplication
`@ConditionalOnExpression` evaluates a SpEL expression — useful when the condition spans multiple properties. `@ConditionalOnWebApplication` / `@ConditionalOnNotWebApplication` restrict beans to web (servlet or reactive) contexts. `@ConditionalOnSingleCandidate` fires only when exactly one candidate bean of the given type exists.
// SpEL over multiple properties
@Bean
@ConditionalOnExpression("''${app.mode}'' == ''standalone'' and ${metrics.enabled:false}")
public MetricsReporter localMetrics() { return new LocalMetricsReporter(); }
// Only in a servlet web application context
@Bean
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public DispatcherServletRegistrationBean registration(DispatcherServlet ds) {
return new DispatcherServletRegistrationBean(ds, "/api/*");
}
// Only if exactly one DataSource bean exists
@Bean
@ConditionalOnSingleCandidate(DataSource.class)
public JdbcTemplate jdbcTemplate(DataSource ds) {
return new JdbcTemplate(ds);
}Writing a Custom @Conditional
When the built-in conditions don't fit, implement `Condition` and pair it with `@Conditional`. The `ConditionContext` gives you access to the environment, class loader, bean factory, and resource loader. Compose into a meta-annotation for reuse across your own starter.
// Custom condition: activate only when running on AWS
public class OnAwsCondition implements Condition {
@Override
public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata meta) {
return ctx.getEnvironment().containsProperty("AWS_REGION")
|| System.getenv("AWS_EXECUTION_ENV") != null;
}
}
// Meta-annotation for readability
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnAwsCondition.class)
public @interface ConditionalOnAws {}
// Usage
@Bean
@ConditionalOnAws
public SecretsManagerClient secretsManagerClient() {
return SecretsManagerClient.create();
}Key Points to Remember
- 1@ConditionalOnClass guards auto-configuration beans on classpath presence
- 2@ConditionalOnMissingBean is the override hook — user-defined beans take precedence
- 3@ConditionalOnProperty enables/disables features via application.properties flags
- 4@ConditionalOnExpression evaluates SpEL for multi-property conditions
- 5All @ConditionalOn* annotations are built on @Conditional(SomeCondition.class)
- 6matchIfMissing=true on @ConditionalOnProperty enables the bean when the property is absent
Interview Questions
Sign in to ask AriaWhat is the difference between @ConditionalOnClass and @ConditionalOnBean?
How does @ConditionalOnMissingBean allow users to override auto-configured beans?
How would you write a custom @Conditional that activates only in a Kubernetes environment?
What does matchIfMissing=true do in @ConditionalOnProperty?
In what order are @ConditionalOn* conditions evaluated during auto-configuration?
Ask Aria about Conditional Beans (@ConditionalOn*)
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.