Spring Boot auto configuration order from external dependency

I have a problem trying to get my autoconfiguration working. I have two jars as follows, each have a spring.factories file where these two are enabled for EnableAutoConfigurationProperties.

This configuration is in my-package-mock.jar, it depends on my-package-real.jar below:

package org.packages.package.packageA;
@Configuration
@AutoConfigureBefore(AutoConfigurationB.class)
public class AutoConfigurationA {

    @Bean
    public MyService mockService() {
        return new MyMockService();
    }
}

This configuration is in my-package-real.jar:

package org.packages.package.packageB;
@Configuration
@ConditionalOnMissingBean(MyService.class)
public class AutoConfigurationB {

    @Bean
    public MyService realService() {
        return new MyRealService();
    }
}

Now the idea is that if my-package-mock.jar is included then AutoConfigurationB will not be processed as A is ordered to be before and by the time it gets to B MyService is already defined. However, it does not work when used in a third project that includes these jars. It looks like the AutoConfigureOrder annotation is skipped when loading these jars from the classpath and these configurations are processed in the order the jvm loads these classes. In my particular case it does B first and at that point MyService is not yet defined and thus will instantiate the RealService bean. How can I get this to work?

Obviously this is a small example where a @Primary annotation on the mock will do the job, but that is not what I'm looking for.

Edit: it seems if the @SpringBootApplication annotated main is not a part of the package where these configurations are then things do work. E.g. the annotation is not in "org.packages.package" but "org.somewhereelse" then things work.

package org.packages.package;

@SpringBootApplication
public class TestApplication {

    public static void main(String[] args) throws Exception {
    SpringApplication.run(Collections.singletonList(TestApplication.class).toArray(), args);
    }
}

Upvotes: 7

Views: 5217

Answers (1)

Andy Wilkinson
Andy Wilkinson

Reputation: 116311

@AutoConfigureBefore and @AutoConfigureAfter only apply when a configuration class is loaded as a result of auto-configuration being enabled and it being listed in spring.factories. When your auto-configuration classes are in org.packages.package (or a sub-package) and your main application class is in the same package, they're being found by Spring Framework's standard component scanning. This happens because @SpringBootApplication enables component scanning for the package of the class that it's annotating. As a result of this the auto-configuration-specific ordering doesn't apply.

To avoid the problem, you should places your auto-configuration classes in a package that isn't used by any application code.

Upvotes: 7

Related Questions