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.
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-
- Use
@Configuration
to register bean in rootcontext
or
dispatchersevletcontext
.
- 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.
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.
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.