Dai Kaixian
Dai Kaixian

Reputation: 1065

How to config @ComponentScan dynamic?

@ComponentScan(  //CS1
    basePackages = {"com.package.A", "com.package.B"},
    excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
                                           value = {com.Package.A.SomeClass.class
                                           })
)

@ComponentScan(  //CS2
    basePackages = { "com.package.A"}
)
@EnableAutoConfiguration
@SpringBootApplication
public class Application {
  public static void main(String[] args) throws Exception {
    ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
  }
}

Above is my SpringBootApplication's main class.As you can see,I have to use Annnotation ,not xml. There are two @ComponentScan Annotations.And it is not permitted for Spring, of course. For me, the two different @ComponentScan means two different way to start up my application. And if I choose to use CS1(it means @ComponentScan1), I hava to comment CS2,and vice versa.

It's not elegant or graceful.Especially for those who are newbie for Spring.So I wonder know how can I config it dynamic according to my .properties file.Such as a param in my .properties file called "isScanA" is ture, then I can use CS1. Or any other elegant way.

I have tried a lot.

  1. Use placeholder. Such as @ComponentScan(basePackage="${scan.basePackage}") .And change the value in .properties file when needed. But this way can't fix the excludeFilters. Because if I use FilterType.ASSIGNABLE_TYPE to assign the class which need to be exclude, the value should be a Class type not a String,where if value = {"${scan.excludeClass}"} be used.

  2. Programmatic way.

    /**
     * Create a new AnnotationConfigApplicationContext, scanning for bean definitions
     * in the given packages and automatically refreshing the context.
     * @param basePackages the packages to check for annotated classes
     */
    public AnnotationConfigApplicationContext(String... basePackages) {
        this();
        scan(basePackages);
        refresh();
    }
    

I called this method in my main function.But it also can't fix the excludeFilters problem, the reason is here:Doing context:component-scan programatic way?

...

I really tried a lot , but still can't fix. So I need your help.

Forgive my poor English, plz.

Thanx a lot, at least you have take a little time to read.

Upvotes: 2

Views: 9188

Answers (2)

Manjunath Mali
Manjunath Mali

Reputation: 1

let's assume you have two packages "com.package.A" and "com.package.B" and you want to always @ComponentScan package.A and want to scan package.B based on some configuration ( defined somewhere in application.properties).

You can add package.A under your application's @ComponentScan and for the other package.B you can just have a @ComponentScan and @ConditionalOnProperty combined together to get it done, where in only if value of property "X" is equal to some "Y" then that @ComponentScan will be rendered and that package will be scanned.

//Normal Application level @ComponentScan
@SpringBootApplication
@ComponentScan(basePackages = { "com.package.A" })

and the other package can be scanned based on some property by

//@ComponentScan which is dependent on property X
@Service
@ConditionalOnProperty(name = "X", havingValue = "Y")
@ComponentScan(basePackages = { "com.package.B"})
@Primary
public class Service extends ServiceImpl { }

Only when property of X is Y com.package.B will be scanned and all beans under it will created else your application will continue to scan only com.package.A

Upvotes: 0

Bruno
Bruno

Reputation: 3089

Maybe you are look for Spring's Profile! Spring Profile allow you to determine profiles for Configurations and Beans. I think you must separate the configuration classes to have two profiles! Take a look at those examples!

Here is the documentation:

http://docs.spring.io/autorepo/docs/spring-boot/current/reference/html/boot-features-profiles.html

Upvotes: 5

Related Questions