How to config @ComponentScan dynamic?
Asked Answered
A

2

2
@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.

Arleta answered 1/11, 2016 at 12:11 Comment(5)
Why do you want to even do this? Looks like you are trying to fix something you shouldn't be fixing in the first place.Chausses
Have a look at Spring Profiles: they sound exactly like what you needGate
@M.Deinum Actually, I am trying to replace the rpc system with direct call in the same jvm. CS2 is the old way to load the service bean which is supported by rpc.And CS1 is the new way to load service bean which can be called in the same jvm. I just want to make two ways choosable for developer.He can start up the app in rpc way or direct calll way.It depends on the value he set in the .properties file.I think it's more graceful than comment the codes.Arleta
Then use Spring Profiles (or property) and use a condition to select a @Configuration to load which has one or the other @ComponentScan.Chausses
@M.Deinum Yeah, I have read the doc about Spring Profile.It can help.ThxArleta
F
5

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

Fairtrade answered 1/11, 2016 at 12:19 Comment(1)
Thx . I have read the doc about Spring Profile. It can help, I think. Thx again.Arleta
P
0

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

Plovdiv answered 1/2 at 7:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.