springspring-bootspring-autoconfiguration

spring boot auto configuration. unexpected behaviour


I am trying to use spring boot auto configuration feature and got an issue. I created a github repo to be able to reproduce easily the "issue":

git clone https://github.com/clembo590/issues.git --branch spring_boot_auto_configuration

just run mvn clean install and you will get all the logs I am refering to in my description.

I have "enabled" the debug=true spring boot property to see which 'autoconfiguration' is activated or not (and if it is not active why it is not active).

I also have added some logs to "log all the beans that have been added to the spring boot context".

Here is my autoConfiguration class.


@Configuration
@ComponentScan(basePackageClasses = MyClass.class)
@ConditionalOnBean(ObjectMapper.class)
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
public class CleaningAutoConfiguration {

    @Bean
    public Fake fake(){
        return new Fake();
    }

    private static class Fake{

    }

}

The very first weird thing is this log:

   CleaningAutoConfiguration:
      Did not match:
         - @ConditionalOnBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) did not find any beans of type com.fasterxml.jackson.databind.ObjectMapper (OnBeanCondition)
      Matched:
         - @ConditionalOnBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) found bean 'jacksonObjectMapper' (OnBeanCondition)

First question: Why is @ConditionalOnBean BOTH matching and Not matching ? (my expectation about such a condition is that it should either match or not match... but not both... see question 5)

Now if we look at the logs it seems that CleaningAutoConfiguration is in the Negative matches: section.

Second question: why is CleaningAutoConfiguration itself registered as a bean ? (I was expecting it would not as it is in the Negative matches section).

Third question: Why is fake still registered as a bean (I was expecting that fake would not be registered, and not even instanciated...)

Fourth question: why is MyClass not registered as a bean ?

Now if you remove the @ComponentScan(basePackageClasses = MyClass.class) then all those questions go away as CleaningAutoConfiguration goes into Positive matches section, but one new is created:

fifth question: Why removing the @ComponentScan brings CleaningAutoConfiguration into Positive matches section ? (maybe question 5 is somehow connected to question 1 .... ?)


Solution

  • The root cause of your problem is the use of @ComponentScan on an auto-configuration class which is not supported:

    Furthermore, auto-configuration classes should not enable component scanning to find additional components. Specific @Imports should be used instead.

    To answer your specific questions:

    Why is @ConditionalOnBean BOTH matching and not matching

    It's first evaluated as part of considering the unsupported @ComponentScan annotation. At this time, the ObjectMapper bean has not been defined so it does not match. It's subsequently evaluated after the ObjectMapper bean has been defined at which point it matches.

    why is CleaningAutoConfiguration itself registered as a bean ? (I was expecting it would not as it is in the Negative matches section).

    The report has mislead you here due to the positive and negative match. CleaningAutoConfiguration is a bean due to the positive match.

    Why is fake still registered as a bean (I was expecting that fake would not be registered, and not even instanciated...)

    The report has misled you again. The conditions on CleaningAutoConfiguration have been matched so its Fake bean has been defined.

    why is MyClass not registered as a bean

    The conditions on CleaningAutoConfiguration did not match when the @ComponentScan annotation was being considered so component scanning of MyClass's package was not enabled.

    Why removing the @ComponentScan brings CleaningAutoConfiguration into Positive matches section

    It prevents the conditions on CleaningAutoConfiguration being evaluated prematurely at a time when the ObjectMapper bean has not yet been defined. When they are eventually evaluated at the expected time, the ObjectMapper bean is present and the conditions match.