I'm learning Spring 3 and I don't seem to grasp the functionality behind <context:annotation-config>
and <context:component-scan>
.
From what I've read they seem to handle different annotations (@Required
, @Autowired
etc vs @Component
, @Repository
, @Service
etc), but also from what I've read they register the same bean post processor classes.
To confuse me even more, there is an annotation-config
attribute on <context:component-scan>
.
Can someone shed some light on these tags? What's similar, what's different, is one superseded by the other, they complete each other, do I need one of them, both?
component-scan
whenever possible.
<context:annotation-config>
is used to activate annotations in beans already registered in the application context (no matter if they were defined with XML or by package scanning).
<context:component-scan>
can also do what <context:annotation-config>
does but <context:component-scan>
also scans packages to find and register beans within the application context.
I'll use some examples to show the differences/similarities.
Let's start with a basic setup of three beans of type A
, B
and C
, with B
and C
being injected into A
.
package com.xxx;
public class B {
public B() {
System.out.println("creating bean B: " + this);
}
}
package com.xxx;
public class C {
public C() {
System.out.println("creating bean C: " + this);
}
}
package com.yyy;
import com.xxx.B;
import com.xxx.C;
public class A {
private B bbb;
private C ccc;
public A() {
System.out.println("creating bean A: " + this);
}
public void setBbb(B bbb) {
System.out.println("setting A.bbb with " + bbb);
this.bbb = bbb;
}
public void setCcc(C ccc) {
System.out.println("setting A.ccc with " + ccc);
this.ccc = ccc;
}
}
With the following XML configuration :
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A">
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
</bean>
Loading the context produces the following output:
creating bean B: com.xxx.B@c2ff5
creating bean C: com.xxx.C@1e8a1f6
creating bean A: com.yyy.A@1e152c5
setting A.bbb with com.xxx.B@c2ff5
setting A.ccc with com.xxx.C@1e8a1f6
OK, this is the expected output. But this is "old style" Spring. Now we have annotations so let's use those to simplify the XML.
First, lets autowire the bbb
and ccc
properties on bean A
like so:
package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import com.xxx.B;
import com.xxx.C;
public class A {
private B bbb;
private C ccc;
public A() {
System.out.println("creating bean A: " + this);
}
@Autowired
public void setBbb(B bbb) {
System.out.println("setting A.bbb with " + bbb);
this.bbb = bbb;
}
@Autowired
public void setCcc(C ccc) {
System.out.println("setting A.ccc with " + ccc);
this.ccc = ccc;
}
}
This allows me to remove the following rows from the XML:
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
My XML is now simplified to this:
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
When I load the context I get the following output:
creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf
OK, this is wrong! What happened? Why aren't my properties autowired?
Well, annotations are a nice feature but by themselves, they do nothing whatsoever. They just annotate stuff. You need a processing tool to find the annotations and do something with them.
<context:annotation-config>
to the rescue. This activates the actions for the annotations that it finds on the beans defined in the same application context where itself is defined.
If I change my XML to this:
<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
when I load the application context I get the proper result:
creating bean B: com.xxx.B@15663a2
creating bean C: com.xxx.C@cd5f8b
creating bean A: com.yyy.A@157aa53
setting A.bbb with com.xxx.B@15663a2
setting A.ccc with com.xxx.C@cd5f8b
OK, this is nice, but I've removed two rows from the XML and added one. That's not a very big difference. The idea with annotations is that it's supposed to remove the XML.
So let's remove the XML definitions and replace them all with annotations:
package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class B {
public B() {
System.out.println("creating bean B: " + this);
}
}
package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class C {
public C() {
System.out.println("creating bean C: " + this);
}
}
package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.xxx.B;
import com.xxx.C;
@Component
public class A {
private B bbb;
private C ccc;
public A() {
System.out.println("creating bean A: " + this);
}
@Autowired
public void setBbb(B bbb) {
System.out.println("setting A.bbb with " + bbb);
this.bbb = bbb;
}
@Autowired
public void setCcc(C ccc) {
System.out.println("setting A.ccc with " + ccc);
this.ccc = ccc;
}
}
While in the XML we only keep this:
<context:annotation-config />
We load the context and the result is... Nothing. No beans are created, no beans are autowired. Nothing!
That's because, as I said in the first paragraph, the <context:annotation-config />
only works on beans registered within the application context. Because I removed the XML configuration for the three beans there is no bean created and <context:annotation-config />
has no "targets" to work on.
But that won't be a problem for <context:component-scan>
which can scan a package for "targets" to work on. Let's change the content of the XML config into the following entry:
<context:component-scan base-package="com.xxx" />
When I load the context I get the following output:
creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff
Hmmmm... something is missing. Why?
If you look closely at the classes, class A
has package com.yyy
but I've specified in the <context:component-scan>
to use package com.xxx
so this completely missed my A
class and only picked up B
and C
which are on the com.xxx
package.
To fix this, I add this other package also:
<context:component-scan base-package="com.xxx,com.yyy" />
and now we get the expected result:
creating bean B: com.xxx.B@cd5f8b
creating bean C: com.xxx.C@15ac3c9
creating bean A: com.yyy.A@ec4a87
setting A.bbb with com.xxx.B@cd5f8b
setting A.ccc with com.xxx.C@15ac3c9
And that's it! Now you don't have XML definitions anymore, you have annotations.
As a final example, keeping the annotated classes A
, B
and C
and adding the following to the XML, what will we get after loading the context?
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
We still get the correct result:
creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87
Even if the bean for class A
isn't obtained by scanning, the processing tools are still applied by <context:component-scan>
on all beans registered in the application context, even for A
which was manually registered in the XML.
But what if we have the following XML, will we get duplicated beans because we've specified both <context:annotation-config />
and <context:component-scan>
?
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
No, no duplications, We again get the expected result:
creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87
That's because both tags register the same processing tools (<context:annotation-config />
can be omitted if <context:component-scan>
is specified) but Spring takes care of running them only once.
Even if you register the processing tools yourself multiple times, Spring will still make sure they do their magic only once; this XML:
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
<bean id="bla" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla1" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla2" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla3" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
will still generate the following result:
creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@25d2b2
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87
OK, that about wraps it up.
I hope this information along with the responses from @Tomasz Nurkiewicz and @Sean Patrick Floyd are all you need to understand how <context:annotation-config>
and <context:component-scan>
work.
I found this nice summary of which annotations are picked up by which declarations. By studying it you will find that <context:component-scan/>
recognizes a superset of annotations recognized by <context:annotation-config/>
, namely:
@Component, @Service, @Repository, @Controller, @Endpoint
@Configuration, @Bean, @Lazy, @Scope, @Order, @Primary, @Profile, @DependsOn, @Import, @ImportResource
As you can see <context:component-scan/>
logically extends <context:annotation-config/>
with CLASSPATH component scanning and Java @Configuration features.
Spring allows you to do two things:
Autowiring of beans Autodiscovery of beans
1. Autowiring
Usually in applicationContext.xml you define beans and other beans are wired using constructor or setter methods. You can wire beans using XML or annotations. In case you use annotations, you need to activate annotations and you have to add <context:annotation-config />
in applicationContext.xml. This will simplify the structure of the tag from applicationContext.xml, because you will not have to manually wire beans (constructor or setter). You can use @Autowire
annotation and the beans will be wired by type.
A step forward for escaping the manual XML configuration is
2. Autodiscovery
Autodiscovery is simplifying the XML one step further, in the sense that you don't even need too add the <bean>
tag in applicationContext.xml. You just mark the specific beans with one of the following annotation and Spring will automatically wire the marked beans and their dependencies into the Spring container. The annotations are as follow: @Controller, @Service, @Component, @Repository. By using <context:component-scan>
and pointing the base package, Spring will auto-discover and wire the components into Spring container.
As a conclusion:
<context:annotation-config>
activates many different annotations in beans, whether they are defined in XML or through component scanning.
<context:component-scan>
is for defining beans without using XML
For further information, read:
3.9. Annotation-based container configuration
3.10. Classpath scanning and managed components
<context:component-scan>
I won't be able to override bean definition using XML?
<context:component-scan>
? Do I loose something if I don't use the <context:annotation-config>
?
<context:annotation-config>
: Scanning and activating annotations for already registered beans in spring config xml.
<context:component-scan>
: Bean registration + <context:annotation-config>
@Autowired and @Required are targets property level so bean should register in spring IOC before use these annotations. To enable these annotations either have to register respective beans or include <context:annotation-config />
. i.e. <context:annotation-config />
works with registered beans only.
@Required enables RequiredAnnotationBeanPostProcessor
processing tool
@Autowired enables AutowiredAnnotationBeanPostProcessor
processing tool
Note: Annotation itself nothing to do, we need a Processing Tool, which is a class underneath, responsible for the core process.
@Repository, @Service and @Controller are @Component, and they targets class level.
<context:component-scan>
it scans the package and find and register the beans, and it includes the work done by <context:annotation-config />
.
The difference between the two is really simple!.
<context:annotation-config />
Enables you to use annotations that are restricted to wiring up properties and constructors only of beans!.
Where as
<context:component-scan base-package="org.package"/>
Enables everything that <context:annotation-config />
can do, with addition of using stereotypes eg.. @Component
, @Service
, @Repository
. So you can wire entire beans and not just restricted to constructors or properties!.
<context:annotation-config>
Only resolves the @Autowired
and @Qualifer
annotations, that's all, it about the Dependency Injection, There are other annotations that do the same job, I think how @Inject
, but all about to resolve DI through annotations.
Be aware, even when you have declared the <context:annotation-config>
element, you must declare your class how a Bean anyway, remember we have three available options
XML:
@Annotations: @Component, @Service, @Repository, @Controller
JavaConfig: @Configuration, @Bean
Now with
<context:component-scan>
It does two things:
It scans all the classes annotated with @Component, @Service, @Repository, @Controller and @Configuration and create a Bean
It does the same job how
Therefore if you declare <context:component-scan>
, is not necessary anymore declare <context:annotation-config>
too.
Thats all
A common scenario was for example declare only a bean through XML and resolve the DI through annotations, for example
<bean id="serviceBeanA" class="com.something.CarServiceImpl" />
<bean id="serviceBeanB" class="com.something.PersonServiceImpl" />
<bean id="repositoryBeanA" class="com.something.CarRepository" />
<bean id="repositoryBeanB" class="com.something.PersonRepository" />
We have only declared the beans, nothing about <constructor-arg>
and <property>
, the DI is configured in their own classes through @Autowired. It means the Services use @Autowired for their Repositories components and the Repositories use @Autowired for the JdbcTemplate, DataSource etc..components
The <context:annotation-config>
tag tells Spring to scan the codebase for automatically resolving dependency requirements of the classes containing @Autowired annotation.
Spring 2.5 also adds support for JSR-250 annotations such as @Resource, @PostConstruct, and @PreDestroy.Use of these annotations also requires that certain BeanPostProcessors be registered within the Spring container. As always, these can be registered as individual bean definitions, but they can also be implicitly registered by including <context:annotation-config>
tag in spring configuration.
Taken from Spring documentation of Annotation Based Configuration
Spring provides the capability of automatically detecting 'stereotyped' classes and registering corresponding BeanDefinitions with the ApplicationContext.
According to javadoc of org.springframework.stereotype:
Stereotypes are Annotations denoting the roles of types or methods in the overall architecture (at a conceptual, rather than implementation, level). Example: @Controller @Service @Repository etc. These are intended for use by tools and aspects (making an ideal target for pointcuts).
To autodetect such 'stereotype' classes, <context:component-scan>
tag is required.
The <context:component-scan>
tag also tells Spring to scan the code for injectable beans under the package (and all its subpackages) specified.
<context:component-scan /> implicitly enables <context:annotation-config/>
try with <context:component-scan base-package="..." annotation-config="false"/>
, in your configuration @Service, @Repository, @Component works fine, but @Autowired,@Resource and @Inject doesn't work.
This means AutowiredAnnotationBeanPostProcessor will not be enabled and Spring container will not process the Autowiring annotations.
<context:annotation-config/> <!-- is used to activate the annotation for beans -->
<context:component-scan base-package="x.y.MyClass" /> <!-- is for the Spring IOC container to look for the beans in the base package. -->
The other important point to note is that context:component-scan
implicitly calls the context:annotation-config
to activate the annotations on beans. Well if you don't want context:component-scan
to implicitly activate annotations for you, you can go on setting the annotation-config element of the context:component-scan
to false
.
To summarize:
<context:annotation-config/> <!-- activates the annotations -->
<context:component-scan base-package="x.y.MyClass" /> <!-- activates the annotations + register the beans by looking inside the base-package -->
<context:component-scan base-package="package name" />
:
This is used to tell the container that there are bean classes in my package scan those bean classes. In order to scan bean classes by container on top of the bean we have to write one of the stereo type annotation like following.
@Component
, @Service
, @Repository
, @Controller
<context:annotation-config />
:
If we don't want to write bean tag explicitly in XML then how the container knows if there is a auto wiring in the bean. This is possible by using @Autowired
annotation. we have to inform to the container that there is auto wiring in my bean by context:annotation-config
.
A <context:component-scan/>
custom tag registers the same set of bean definitions as is done by , apart from its primary responsibility of scanning the java packages and registering bean definitions from the classpath.
If for some reason this registration of default bean definitions are to be avoided, the way to do that is to specify an additional "annotation-config" attribute in component-scan, this way:
<context:component-scan basePackages="" annotation-config="false"/>
Reference: http://www.java-allandsundry.com/2012/12/contextcomponent-scan-contextannotation.html
<context:annotation-config>
:
This tells Spring that I am going to use Annotated beans as spring bean and those would be wired through @Autowired
annotation, instead of declaring in spring config xml file.
<context:component-scan base-package="com.test...">
:
This tells Spring container, where to start searching those annotated beans. Here spring will search all sub packages of the base package.
you can find more information in spring context schema file. following is in spring-context-4.3.xsd
<conxtext:annotation-config />
Activates various annotations to be detected in bean classes: Spring's @Required and
@Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available),
JAX-WS's @WebServiceRef (if available), EJB 3's @EJB (if available), and JPA's
@PersistenceContext and @PersistenceUnit (if available). Alternatively, you may
choose to activate the individual BeanPostProcessors for those annotations.
Note: This tag does not activate processing of Spring's @Transactional or EJB 3's
@TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>
tag for that purpose.
<context:component-scan>
Scans the classpath for annotated components that will be auto-registered as
Spring beans. By default, the Spring-provided @Component, @Repository, @Service, @Controller, @RestController, @ControllerAdvice, and @Configuration stereotypes will be detected.
Note: This tag implies the effects of the 'annotation-config' tag, activating @Required,
@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and @PersistenceUnit
annotations in the component classes, which is usually desired for autodetected components
(without external configuration). Turn off the 'annotation-config' attribute to deactivate
this default behavior, for example in order to use custom BeanPostProcessor definitions
for handling those annotations.
Note: You may use placeholders in package paths, but only resolved against system
properties (analogous to resource paths). A component scan results in new bean definitions
being registered; Spring's PropertySourcesPlaceholderConfigurer will apply to those bean
definitions just like to regular bean definitions, but it won't apply to the component
scan settings themselves.
As a complementary, you can use @ComponentScan
to use <context:component-scan>
in annotation way.
It's also described at spring.io
Configures component scanning directives for use with @Configuration classes. Provides support parallel with Spring XML's element.
One thing to note, if you're using Spring Boot, the @Configuration and @ComponentScan can be implied by using @SpringBootApplication annotation.
Success story sharing