What is @Conditional and the Condition interface in Spring, and how do you use them to register a bean only under certain circumstances?
answer
- Condition.matches(ctx, metadata) -> boolean
- All conditions AND-combined; false = definition skipped
- Evaluated at config-parse time, before instantiation
- ConditionContext: registry, beanFactory, environment, classLoader
- Boot's @ConditionalOnX are meta-@Conditional
basics
~10 s@Conditional is an annotation you put on a @Bean or @Configuration. It points to a class implementing the Condition interface, whose matches() method returns true/false. Spring registers the bean only when matches() returns true.
solid answer
~40 s@Conditional(SomeCondition.class) is a general-purpose annotation, placed on a @Bean method, @Configuration class, or any @Component, that gates whether that bean definition is registered at all. You supply one or more classes implementing the functional Condition interface: boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata). Spring evaluates it during bean-definition processing; if it returns false the definition is skipped entirely — the bean never exists, so nothing can inject it. All listed conditions must match (logical AND). ConditionContext gives access to the BeanFactory, Environment, ResourceLoader, ClassLoader, and BeanDefinitionRegistry so the condition can inspect properties, classpath, or already-registered beans. This is the exact mechanism Spring Boot's @ConditionalOnClass, @ConditionalOnProperty, and @ConditionalOnMissingBean are built on — they are meta-annotated with @Conditional.
code
java · 16 linespublic class OnFeatureFlagCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String flag = context.getEnvironment().getProperty("features.reporting");
return "enabled".equalsIgnoreCase(flag);
}
}
@Configuration
class ReportingConfig {
@Bean
@Conditional(OnFeatureFlagCondition.class)
ReportingService reportingService() {
return new ReportingService();
}
}go deeper
Know it gates a @Bean via a Condition class whose matches() returns true/false, evaluated before the bean is created.
Explain the matches signature, ConditionContext contents, AND-combination, and that Boot's @ConditionalOnX are built on it.
Discuss evaluation timing during config parsing, using getRegistry vs getBeanFactory, and downstream injection consequences of a skipped definition.
Frame it as the extension point for auto-configuration, note phase/ordering concerns and how starters compose meta-annotated conditions.
**The problem it solves.** Sometimes a bean should only exist under certain runtime conditions — a class is on the classpath, a property is set, no other bean of that type was already defined, etc. Rather than register the bean and fail later, `@Conditional` decides *at configuration time* whether the bean definition is created at all. **The annotation.** `org.springframework.context.annotation.@Conditional` takes one or more `Class<? extends Condition>` values: `@Conditional({A.class, B.class})`. You can place it on: - a `@Bean` factory method (gates just that bean), - a `@Configuration` class or any `@Component` (gates the class and, for a config class, all beans it declares), - another annotation (meta-annotation), which is how composed conditions like Boot's are built. **The Condition SPI.** `org.springframework.context.annotation.Condition` is a functional interface: ```java boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); ``` - `ConditionContext` exposes: `getRegistry()` (BeanDefinitionRegistry — what's registered so far), `getBeanFactory()` (may be null in some phases), `getEnvironment()` (properties/profiles), `getResourceLoader()`, and `getClassLoader()`. - `AnnotatedTypeMetadata` describes the annotated element — you can read attributes of annotations present on it (e.g. which class/property a composed condition was configured with). **Semantics.** If **all** conditions return `true`, the definition is kept; if **any** returns `false`, it is skipped — no bean, no proxy, nothing to autowire. Conditions are AND-combined; there is no built-in OR (you compose that inside a single condition or via meta-annotation logic). **Evaluation timing.** Conditions run while the `ConfigurationClassPostProcessor` parses configuration classes and registers bean definitions — *before* bean instantiation. So conditions decide structure, not runtime behavior. **Common gotchas.** - A plain `Condition` is evaluated during config parsing; if it inspects the `BeanFactory` for other beans, ordering matters — see `ConfigurationCondition`/`ConfigurationPhase` for controlling that. - `context.getBeanFactory()` can be limited early; prefer `getRegistry()` to check whether a definition exists. - Because a false condition removes the definition entirely, downstream `@Autowired` on that type will fail unless it's marked optional or another bean supplies it. **When to use.** Library/starter authors use it for opt-in beans; app code more often uses the higher-level Boot conditions (`@ConditionalOnProperty`, `@ConditionalOnClass`, `@ConditionalOnMissingBean`) which are just `@Conditional` compositions. Note profile activation (`@Profile`) is a separate, higher-level mechanism (itself internally a condition) and is out of scope here.
- What are the two arguments to Condition.matches() and what do you get from each?ConditionContext (getRegistry, getBeanFactory, getEnvironment, getResourceLoader, getClassLoader) and AnnotatedTypeMetadata (annotations/attributes on the annotated element, so a composed condition can read how it was configured).
- If two conditions are listed in @Conditional, is the result AND or OR?AND — every listed Condition must return true for the definition to be kept; any false skips it. There is no built-in OR.
saying these in an interview costs you the question
- Saying the bean is created but stays a no-op — a false condition removes the definition entirely, the bean never exists
- Claiming @Conditional runs at runtime per-request — it runs once, at configuration/bean-definition time
- Confusing @Conditional with @Profile (profiles are a separate sibling mechanism)
- Thinking multiple conditions are OR-ed