Description

If two bean factories (@Configuration) define the same bean, having one defines it without any conditions and another using @ConditionalOnMissingBean it is important in this situation to pay attention to the order of classes with these factories when they are injected into @SpringBootApplication via @Import.

It is important that the bean factory with a conditional bean goes first, before the one without a conditional bean, otherwise, there will be a startup error.

And the opposite situation happens for tests. This time the bean factory without a conditional bean must go first, before the one with a conditional bean.

Reproducer

Repo: https://github.com/alexey-anufriev/spring-boot-test-classes-order Detailed problem description: https://github.com/alexey-anufriev/spring-boot-test-classes-order/blob/master/README.md Case 1: Try to run SecondaryApp that works fine, and PrimaryApp that fails. Case 2: Try to run PrimaryTest that works fine, and SecondaryTest that fails.

Expected Results

No matter what is the order of classes, the context is being built only by having all the bean factories scanned first, and the decision about what bean to put in the context is made once all bean alternatives are known. But it seems that the Spring context is being populated sequentially, step-by-step for each bean factory detected among configured classes.

Comment From: mbhave

@alexey-anufriev Thanks for the sample.

@ConditionalOnMissingBean is only meant to be used in auto-configurations, the javadoc for this class says:

The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only. If a candidate bean may be created by another auto-configuration, make sure that the one using this condition runs after.

Comment From: alexey-anufriev

@mbhave, thank you for your answer. Could you recommend a way to fill the context conditionally and reliably, without ordering-related concerns?

Comment From: philwebb

... the context is being built only by having all the bean factories scanned first, and the decision about what bean to put in the context is made once all bean alternatives are known

@alexey-anufriev When we looked at adding @Condition support to Spring Framework we did consider trying to create a complete bean graph and then applying the conditions afterward. Unfortunately it turned out to be very difficult due to the way that Spring Framework manages beans under the hood. For example, with conditions it's fine to have multiple beans use the same name, as long as they're not active at the same time. Limiting our own conditions to auto-configuration and having @AutoConfigureBefore/@AutoConfigureAfter turned out to be the most pragmatic way to solve the problem.

I'm afraid it's very unlikely that we can change such a key design decision at this point, especially as it's working well enough for our own needs. I think the @Import annotation is probably the only way to define the order that bean definitions get added.