Home/Learn/Spring Boot/Conditional Beans (@ConditionalOn*)

Conditional Beans (@ConditionalOn*)

Intermediate
Core & Setup

@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.

Spring Boot — @ConditionalOnClass / MissingBean / Property
@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.

Spring Boot — @ConditionalOnExpression and web conditions
// 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.

Spring Boot — custom Condition implementation
// 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 Aria
1

What is the difference between @ConditionalOnClass and @ConditionalOnBean?

MediumPivotal
2

How does @ConditionalOnMissingBean allow users to override auto-configured beans?

MediumThoughtWorks
3

How would you write a custom @Conditional that activates only in a Kubernetes environment?

HardRed Hat
4

What does matchIfMissing=true do in @ConditionalOnProperty?

EasyAccenture
5

In what order are @ConditionalOn* conditions evaluated during auto-configuration?

HardVMware

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.

Loading discussion…