redhead
redhead

Reputation: 1317

Conditional ComponentScan on package

In a Spring Boot Application I have a package with Application class like

@SpringBootApplication
class Application {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(Application);
        application.run(args);
    }

}

which automatically has ComponentScan set up from that class's package by default. Then I have several subpackages each containing several component and service beans (using annotations). But for the purpose of reuse of this application for different use cases, I need to enable/disable all the components in some of the subpackages, preferably by a property.

That is I have subpackages like

org.example.app.provider.provider1
org.example.app.provider.provider2

Now, based on some property I would like to enable (scan for) beans in one of the packages, e.g.

provider1.enabled=true

I thought I could make ConditionalOnProperty on Configuration class work like that, but the problem is, that the beans are picked up by the default @SpringBootApplication component scan (i.e. the subpackage Configuration class does not override the top level one)

So I thought I would exclude the packages, but this adds more work (and knowledge) when a new provider package is needed (need to know in advance to add an explicit exclude for that package).

Is there any other way how to do this I can't figure out?

Upvotes: 12

Views: 10383

Answers (1)

alexbt
alexbt

Reputation: 17025

Load the provider components conditionally

A Spring Configuration annotated with a @ConditionalOnProperty would do just that:

@Configuration
@ComponentScan("org.example.app.provider.provider1")
@ConditionalOnProperty(name = "provider1.enabled", havingValue = "true")
public class Provider1Configuration {
}

@Configuration
@ComponentScan("org.example.app.provider.provider2")
@ConditionalOnProperty(name = "provider2.enabled", havingValue = "true")
public class Provider2Configuration {
}

Then exclude the components under org.example.app.provider.*

Now, all you need is to exclude the providers from Spring Boot Application (and let the CondtionalOnProperty do its work). You can either:

  • (1) move the provider packages so that they are not below the Spring Boot Application

For example, if the Spring Boot main is in org.example.app, keep the @Configuration in org.example.app but the providers in org.example.providers

  • (2) Or exclude the provider package from Spring Boot (assuming the @Configuration are in org.example.app for example):

SpringBootMain.java:

@SpringBootApplication
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "org.example.app.provider.*"))
class Application {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(Application);
        application.run(args);
    }
}

Upvotes: 18

Related Questions