Conditional Beans (@Conditional)
Conditional Beans (@Conditional)
Spring's IoC container is remarkably flexible: you can tell it to register a bean only when a specific condition is met at startup — a property value, an environment profile, the presence or absence of another class on the classpath, and much more. This is the mechanism behind Spring Boot's famous auto-configuration, and understanding it lets you write configuration classes that adapt intelligently to different environments without a single if statement in your business code.
The Core Abstraction: Condition and @Conditional
Every conditional bean check is built on one interface: org.springframework.context.annotation.Condition. It has a single method:
ConditionContext gives you access to the BeanDefinitionRegistry, the ConfigurableListableBeanFactory, the Environment, the ResourceLoader, and the ClassLoader. That means a custom condition can inspect anything Spring knows about at startup time.
You attach a condition to any @Bean method or @Configuration class using @Conditional(YourCondition.class). If matches() returns false, that bean definition is silently skipped — no error, no placeholder.
Built-in Conditions in Spring Boot
Spring Boot ships a rich set of ready-made conditions in the org.springframework.boot.autoconfigure.condition package. These are the building blocks of every auto-configuration starter:
@ConditionalOnProperty— registers the bean only when a property key has a specific value.@ConditionalOnClass/@ConditionalOnMissingClass— based on a class being present or absent on the classpath.@ConditionalOnBean/@ConditionalOnMissingBean— based on whether another bean is (or is not) already registered.@ConditionalOnExpression— evaluated against a SpEL expression.@ConditionalOnWebApplication/@ConditionalOnNotWebApplication— based on the application type.@ConditionalOnCloudPlatform— matches a specific deployment platform such as Kubernetes or Cloud Foundry.
Practical Example: Feature-Flag Bean
Suppose a notification service should send real emails in production but write to the console locally. Use @ConditionalOnProperty to switch implementations based on a flag:
matchIfMissing = true on a fallback bean. Combine it with @ConditionalOnMissingBean to guarantee exactly one implementation is registered even when the property is absent. This pattern appears throughout Spring Boot's auto-configurations.
@ConditionalOnMissingBean: The Extensibility Pattern
The most powerful pattern in Spring Boot auto-configuration is back-off: provide a sensible default but let the application developer override it simply by declaring their own bean of the same type.
If the application declares its own CacheManager — say, a Redis-backed one — the auto-configuration backs off silently. No exclusion needed, no property flag. The application's explicit bean takes precedence because Spring processes @Configuration classes in the application before auto-configurations.
Writing a Custom Condition
When no built-in annotation fits, implement Condition directly. Here is a condition that activates a bean only when the application is running on Linux:
For reuse across projects, wrap the condition in a composable meta-annotation:
Now any @Bean method or @Configuration class can simply annotate with @ConditionalOnLinux.
@ConditionalOnExpression for Dynamic Logic
When the condition is best expressed as a Boolean formula over properties, use SpEL:
matches(). A slow condition delays every application startup.
Ordering and Evaluation Order
When a condition checks for the presence of another bean (@ConditionalOnBean), ordering matters. If configuration class B needs to register after class A so it can see A's beans, use @AutoConfigureAfter (in auto-configurations) or @DependsOn (for explicit ordering in application code). Without ordering, the result is non-deterministic.
For regular application @Configuration classes that you control, prefer @ConditionalOnMissingBean over @ConditionalOnBean because you can reason about it without worrying about evaluation order: the condition is essentially "if nobody else registered this type, I will."
Trade-offs and Best Practices
- Prefer property-based conditions over class-based ones in application code — they are easier to override in tests by setting properties.
- Avoid nesting too many conditions on one bean. If you need three conditions all satisfied, extract a dedicated
@Configurationclass and apply the conditions there so they read as a cohesive policy. - Document non-obvious conditions with a comment explaining what must be true for the bean to register. Future maintainers (and future you) will thank you.
- Test conditional beans explicitly. Use
ApplicationContextRunnerin unit tests to verify which beans register under each combination of conditions without starting a full server.
Summary
Conditional beans give Spring's container the ability to self-configure based on the runtime environment. The Condition interface is the single extensible hook; all of Spring Boot's auto-configuration annotations — @ConditionalOnProperty, @ConditionalOnMissingBean, @ConditionalOnClass, and the rest — are composable, reusable implementations of that one interface. Write custom conditions when no built-in annotation fits, wrap them in meta-annotations for reuse, and test every conditional path with ApplicationContextRunner to keep your configuration reliable across all environments.