@ComponentScan with multiple configuration class :

2020-05-28 10:53发布

问题:

As per Spring Doc-

Configures component scanning directives for use with @Configuration classes. Provides support parallel with Spring XML's <context:component-scan> element.

In my spring web application there are multiple files those are marked @Configuration,in order to register @component bean in spring container-

Question1- Can we use @ComponentScan in any of the @Configuration class or in all @Configuration classes?

Question2-

Also I seen in spring doc

@Configuration
@ComponentScan(basePackageClasses = { MyConfiguration.class })
public class MyConfiguration extends WebMvcConfigurerAdapter {
...
}

Why here scanning for configuration class itself.

edit: Basically my understanding with @ComponentScan is to scan and register stereo type bean(ex- @componant,@Controller,@Services etc..),why we are registering @Configuration Bean.

回答1:

For your Question 1 -

yes, you can register a bean using @ComponentScan in any of the configuration bean which is registered in spring container.you can register a bean into container by any of the following way-

  1. Use @Configuration to register bean in rootcontext or dispatchersevletcontext.
  2. Import a class in any @Configuration bean (which is already registered in container).

Let say- you have MvcConfig class in which you are scanning component-

@ComponentScan(basePackages = {"xxxx","yyyy","zzzz"})
@Configuration
public class MvcConfig  {
....
}

To register MvcConfig in container you must do-

Either

new AnnotationConfigWebApplicationContext().register(MvcConfig.class);

Or

new AnnotationConfigWebApplicationContext().register(AnotherConfig.class);

@Configuration
@Import({MvcConfig.class})
public class AnotherConfig  {
....
}

For your Question 2 -

Here spring is not only registering MyConfiguration.class but also all the component classes those are present in the package in which MyConfiguration defined.



回答2:

Solution to Question 1:
Yes, You can use @Componentscan in as many configuraion classes. That is all up to you. It just registers the various annotated classes of some specific packages as beans. So if you have all the annotated classes component scanned by just using one @Componentscan, that is enough, as all the required beans you wanted has been activated and registered in the DispatcherServlet container.

Solution to Question 2:

@Configuration
@ComponentScan(basePackageClasses = { MyConfiguration.class })
public class MyConfiguration extends WebMvcConfigurerAdapter {
...
}

Your question: Why here scanning for configuration class itself?
This @ComponentScan(basePackageClasses = { MyConfiguration.class }) is mentioning MyConfiguration.class as example. The question is what does this mean?

There are two ways to componentscan packages either by basepackage attribute or basepackageclasses. These two are same but using basepackageclasses has two benefits which are:
It is both type-safe and adds IDE support for future refactoring
That simply means, in future, you may rename (via refactor) some of the base backages, and since you have renamed the base packages, you do not need to change @ComponentScan in your configuration classes if you have used basepackageclasses attribute.

Now coming back to your 2nd question. Why MyConfiguration.class is specified as the value of basepackageclasses attribute of @Componentscan?

First of all, let us know this:
basepackageclasses attribute takes string value which represents some marker class. That Marker class tells: Hey! register all the classes which are present in the package in which this class is present, including this class

So, here in your answer, all those classes will be component-scanned which are present in the package in which MyConfiguration.class is present.

Hence, Myconfiguration.class acts as the Configuration class as well as the marker class to component scan other classes as well. Which also implies all the annotated classes will get registered which are present in the package in which MyConfiguration.class is present, including MyConfiguration.class as it is annotated with @Configuration annotation

basepackageclasses attribute can have other classes as well, like com.abc.org.Marker.class

Benefit:
So, if you rename packages, there is no problem, as you have marker classes, which help spring find the packages. These marker classes may or may not have any content inside, as it just acts as a marker to find packages.



回答3:

From the documentation:

Q1:

@Configuration is meta-annotated with @Component, therefore @Configuration classes are candidates for component scanning (typically using Spring XML's element) and therefore may also take advantage of @Autowired/@Inject like any regular @Component.

@Configuration classes may not only be bootstrapped using component scanning, but may also themselves configure component scanning using the @ComponentScan annotation:

@Configuration
@ComponentScan("com.acme.app.services")
public class AppConfig {
 // various @Bean definitions ...
}

Q2:

basePackageClasses

public abstract Class<?>[] basePackageClasses

Type-safe alternative to basePackages() for specifying the packages to scan for annotated components. The package of each class specified will be scanned.


Answer for your edited question

At some point you need to say to Spring where the beans your app needs are. You can use for example:

public static void main(String[] args) {  
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.scan("com.acme");  
    ctx.refresh();
    MyService myService = ctx.getBean(MyService.class);
}

or using old xml style:

<context:component-scan base-package="com.acme" />

Using @ComponentScan at @Configuration level you are making sure all the dependencies for that config class are going to be available. Using @CompenentScan with basePackageClasses you are registering all the components available under the same package the class specified is.

If you have already let spring know what packages it needs to scan, in a different place or way, you do not need to use it. The piece of code at your Q2 is just an example of what spring is able to do.