Using Spring v5.3.27 with Spring Boot v2.7.12 and @ConditionalOnBean annotation for the classes annotated with @Component I receive non-deterministic beans initialization (presence) depending on the way I run the application. For instance, if I run it via mvn spring-boot:run my conditions work well, but if I mvn package a jar and then run it via java -jar ... then some of the beans get initialized despite that the @ConditionalOnBean should return false.

I'm aware of the comment on @ConditionalOnBean saying that 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.

Though, it's way easier to assign a @Component annotation on a class and rely on Component Scan rather than writing a lot of wiring code that requires maintenance and increases the complexity of the application.

Thus. I'd like to discuss the limitation and the way to remove it.

My analysis of the relevant business logic implementation led me to the ClassPathScanningCandidateComponentProvider class and its scanCandidateComponents method. There, depending on the order of the resources fetched via getResourcePatternResolver().getResources(packageSearchPath), candidates get checked via isCandidateComponent and isConditionMatch using MetadataReader associated with the resource.

The first idea is to order the resource based on a priority that is based on the presence or absence of the @Conditional annotations as well as the annotation class. E.g. having @ConditionalOnBean, @ConditionalOnMissingBean, and @ConditionalOnSingleCandidate evaluated with the lowest priority.

I see that the mentioned annotations come from Spring Boot, thus the Condition interface could be extended to have a method that could be used to get the required metadata for the ordering.

I guess that I'm not the first one who challenged this point, if so, then I'd appreciate sharing your thoughts on why it's all a bad idea and the way it's implemented at the moment is the best one considering all things.

Cheers and thank you for such an amazing and inspiring framework!

Comment From: gallyamb

Not sure, but maybe it's somehow related to the https://github.com/spring-projects/spring-framework/issues/28337

Comment From: Gems

Thank you @gallyamb though it looks like a different problem to me

Comment From: snicoll

Though, it's way easier to assign a @Component annotation on a class and rely on Component Scan rather than writing a lot of wiring code that requires maintenance and increases the complexity of the application.

I would argue relying on component scan and using @ConditionalOnBean is actually increasing the complexity of the application for the reason described in the Javadoc.

I guess that I'm not the first one who challenged this point, if so, then I'd appreciate sharing your thoughts on why it's all a bad idea and the way it's implemented at the moment is the best one considering all things.

Expecting component scan to give you a reliable order, including when the application evolves is setting the wrong expectation. Even if we managed to provide some sort of ordering, it could easily break in subtle ways, such as with code refactoring: changing the name, package and/or location of a @Component could lead to breaking conditions. In a nutshell, the comment in the Javadoc remains: if you are using @ConditionalOnMissingBean for a type, you need to make sure whatever is contributing such type is evaluated first. You could use @Import({A.class, B.class, C.class})to define such order and that doesn't looks like a lot of code to me.

Comment From: Gems

Thank you for the feedback @snicoll

I'll give the @Import option for ordering a try and see if it makes the trick. It wasn't intuitively understandable that @Import would affect and define the order.

On the related matter. Judging by your comments I can see that you consider some sort of alphabetical order or similar, that indeed could be easily unintentionally broken on refactoring.

While I'm proposing an order based on @Conditional annotations and their potential impact on the initialization of beans. Of course, it most likely requires an extension of the Condition interface to provide additional metadata for ordering and other related aspects. On the other hand, this approach makes the user configuration cleaner and reduces the likelihood of errors in the tool using.

I would be happy to discuss and contribute further with your support or someone else's, to ensure that the design aligns with the framework's philosophy and other important aspects.

Comment From: snicoll

I understood, I think, what you're heading at but I don't see how an algorithm that orders classpath-detected components could be more intuitive than a well defined order. I don't think it could ever be, and such algorithm would therefore be a way to avoid defining the components that are target for conditions, and rather rely on component scan. My point is that I believe component scan to be wrong tool for defining components that rely on conditions.

That's also why we think such conditions should be applied on auto-configurations only, where they have relative ordering with auto-configure before and after.

All in all, I don't agree that this makes the configuration cleaner. Surely there's an intermediate layer that is not needed (the @Configuration, and the order at which they are processed), but that's precisely the point of understanding exactly in which context the various conditions apply. It's more than a preference in this case, and I don't understand why defining those components is such an hassle considering you need to make sure the conditions evaluate against the right state of the bean factory.

Feel free to investigate on your end and we can continue the discussion based on code as I think it would be easier to argue the merits of one vs. the other.