Affects: 4.3.x - 5.1.x
Probably affects older versions as well.
When @ConditionalOn..
annotations are used on @Bean
methods with the same name within one configuration class, the outcome depends on the declaration order of the methods.
Consider the simple example, in which application startup fails, because the bean name 'conditionalBean' becomes blacklisted on the upper definition, thus the second one is ignored.
@SpringBootApplication
@Configuration
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
@ConditionalOnExpression("false")
public ConditionalBean conditionalBean(ApplicationContext ctx) {
return new ConditionalBean();
}
@Bean
public ConditionalBean conditionalBean() {
return new ConditionalBean();
}
@Bean
public SomeOtherBean someOtherBean(ConditionalBean conditionalBean) {
return new SomeOtherBean();
}
public class ConditionalBean {}
public class SomeOtherBean {}
}
In this example the application starts up properly:
@Bean
public ConditionalBean conditionalBean() {
return new ConditionalBean();
}
@Bean
@ConditionalOnExpression("false")
public ConditionalBean conditionalBean(ApplicationContext ctx) {
return new ConditionalBean();
}
The reason for this behavior lies in ConfigurationClassBeanDefinitionReader::loadBeanDefinitionsForBeanMethod
, where the method name is internally stored as skipped:
// Do we need to mark the bean as skipped by its condition?
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
A sample project to reproduce this error can be found here: https://github.com/tobisinghania/spring-conditionaOn-order
Comment From: redhead
Hi. Just ran into this and was quite surprised by this behavior.
For me, it even works differently than described above where it depends on the order of method declaration: in my case, the order of the methods in the introspection is non-deterministic and can differ with every application run. When the method with matching Conditional is introspected first, the bean is created and the second method is skipped. If the bean method with non-matching Conditional goes first, both are ignored.
Any reason why the fix is not merged yet?
Comment From: hbourada
I got same problem as @tobisinghania where I have several @Bean
method names in my auto-configuration class with different signatures and exclusives @Conditional
so that only one bean will be instanciated, the problem is effectively in configClass.skippedBeanMethod
as montionned.
Comment From: snicoll
When @ConditionalOn.. annotations are used on @Bean methods with the same name within one configuration class, the outcome depends on the declaration order of the methods.
I am afraid that it is the expected behavior. Conditions are evaluated in order and are linked to their bean definitions. Also the configuration above is invalid as you're trying to register the same bean twice. Not two variants of the same bean with condition evaluation. Literally the same bean as they share the same identifier.