context:component-scan vs context:annotation-config
context:annotation-config
This tag is used to activate the annotations inside the beans which are already registered with the Application context.
Basically it is used for Autowiring.
Context:component-scan
This tag does what context:annotation-config does and in addition to that it also scans the packages and registers the stereotype annotated classes as a spring beans.
Detailed example to understand the same
Let’s start with 3 classes Person,Car,Address. Person is having has a relationship with Car and Address.
- package com.kb.componentscan_annotationconfig;
- public class Car {
- public Car() {
- System.out.println("creating the Car bean "+this);
- }
- }
package com.kb.componentscan_annotationconfig; public class Car { public Car() { System.out.println("creating the Car bean "+this); } }
Address.java
- package com.kb.componentscan_annotationconfig;
- public class Address {
- public Address() {
- System.out.println("creating the Address bean "+this);
- }
- }
package com.kb.componentscan_annotationconfig; public class Address { public Address() { System.out.println("creating the Address bean "+this); } }
Person.java
- package com.kb.componentscan_annotationconfig;
- public class Person {
- private Car car;
- private Address address;
- public Person() {
- System.out.println("creating the Person bean "+this);
- }
- public Car getCar() {
- return car;
- }
- public void setCar(Car car) {
- System.out.println("setting car bean with"+car);
- this.car = car;
- }
- public Address getAddress() {
- return address;
- }
- public void setAddress(Address address) {
- System.out.println("setting address bean with "+address);
- this.address = address;
- }
- }
package com.kb.componentscan_annotationconfig; public class Person { private Car car; private Address address; public Person() { System.out.println("creating the Person bean "+this); } public Car getCar() { return car; } public void setCar(Car car) { System.out.println("setting car bean with"+car); this.car = car; } public Address getAddress() { return address; } public void setAddress(Address address) { System.out.println("setting address bean with "+address); this.address = address; } }
beans.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <bean id="person" class="com.kb.componentscan_annotationconfig.Person">
- <property name="car" ref="car"/>
- <property name="address" ref="address"/>
- </bean>
- <bean id="car" class="com.kb.componentscan_annotationconfig.Car"/>
- <bean id="address" class="com.kb.componentscan_annotationconfig.Address"/>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="person" class="com.kb.componentscan_annotationconfig.Person"> <property name="car" ref="car"/> <property name="address" ref="address"/> </bean> <bean id="car" class="com.kb.componentscan_annotationconfig.Car"/> <bean id="address" class="com.kb.componentscan_annotationconfig.Address"/> </beans>
MainClient.java
- package com.kb.componentscan_annotationconfig;
- import org.springframework.beans.BeansException;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class MainClient {
- public static void main(String[] args) {
- ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/kb/componentscan_annotationconfig/beans.xml");
- }
- }
package com.kb.componentscan_annotationconfig; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainClient { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/kb/componentscan_annotationconfig/beans.xml"); } }
Run the client to see the output
Output is as expected and dependency injection is achived with XML.
Now lets try to use annotation for DI.
Now class Person becomes as below after autowiring
Person.java
- package com.kb.componentscan_annotationconfig;
- import org.springframework.beans.factory.annotation.Autowired;
- public class Person {
- private Car car;
- private Address address;
- public Person() {
- System.out.println("creating the Person bean "+this);
- }
- public Car getCar() {
- return car;
- }
- @Autowired
- public void setCar(Car car) {
- System.out.println("setting car bean with"+car);
- this.car = car;
- }
- public Address getAddress() {
- return address;
- }
- @Autowired
- public void setAddress(Address address) {
- System.out.println("setting address bean with "+address);
- this.address = address;
- }
- }
package com.kb.componentscan_annotationconfig; import org.springframework.beans.factory.annotation.Autowired; public class Person { private Car car; private Address address; public Person() { System.out.println("creating the Person bean "+this); } public Car getCar() { return car; } @Autowired public void setCar(Car car) { System.out.println("setting car bean with"+car); this.car = car; } public Address getAddress() { return address; } @Autowired public void setAddress(Address address) { System.out.println("setting address bean with "+address); this.address = address; } }
Now I have used autowiring to inject Car and Address, so remove those lines from xml
- <property name="car" ref="car"/>
- <property name="address" ref="address"/>
<property name="car" ref="car"/> <property name="address" ref="address"/>
And now xml is as below
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <bean id="person" class="com.kb.componentscan_annotationconfig.Person"/>
- <bean id="car" class="com.kb.componentscan_annotationconfig.Car"/>
- <bean id="address" class="com.kb.componentscan_annotationconfig.Address"/>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="person" class="com.kb.componentscan_annotationconfig.Person"/> <bean id="car" class="com.kb.componentscan_annotationconfig.Car"/> <bean id="address" class="com.kb.componentscan_annotationconfig.Address"/> </beans>
Now run our client to load application context
Output
Why we didn’t get setter method’s output means, why Car and Address are not injected to Person even though we used @Autowired ?
Yes this is because Annotation are good feature by themselves but they are just annotated they cant do any processing.
We need some processing element which finds those annotations and perform the corresponding action.
Yes that processing element for Autowiring is < context:annotation-config >
This will perform the corresponding action based on the annotation defined inside the registered beans.
Now modify our beans.xml as below
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <bean id="person" class="com.kb.componentscan_annotationconfig.Person"/>
- <bean id="car" class="com.kb.componentscan_annotationconfig.Car"/>
- <bean id="address" class="com.kb.componentscan_annotationconfig.Address"/>
- <context:annotation-config/>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="person" class="com.kb.componentscan_annotationconfig.Person"/> <bean id="car" class="com.kb.componentscan_annotationconfig.Car"/> <bean id="address" class="com.kb.componentscan_annotationconfig.Address"/> <context:annotation-config/> </beans>
We have just added our processing element for autowiring.
We can add it at the beginning or end – does not matter.
Now see the output
It means context:annotation-config reduced bit of xml coding(ie adding bean
references)
Now I am not happy with just 2 lines removal from xml.
So lets remove all the lines from xml and annotate our class with @Component.
- package com.kb.componentscan_annotationconfig;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
- @Component
- public class Person {
- private Car car;
- private Address address;
- public Person() {
- System.out.println("creating the Person bean "+this);
- }
- public Car getCar() {
- return car;
- }
- @Autowired
- public void setCar(Car car) {
- System.out.println("setting car bean with"+car);
- this.car = car;
- }
- public Address getAddress() {
- return address;
- }
- @Autowired
- public void setAddress(Address address) {
- System.out.println("setting address bean with "+address);
- this.address = address;
- }
- }
package com.kb.componentscan_annotationconfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class Person { private Car car; private Address address; public Person() { System.out.println("creating the Person bean "+this); } public Car getCar() { return car; } @Autowired public void setCar(Car car) { System.out.println("setting car bean with"+car); this.car = car; } public Address getAddress() { return address; } @Autowired public void setAddress(Address address) { System.out.println("setting address bean with "+address); this.address = address; } }
Car.java
- package com.kb.componentscan_annotationconfig;
- import org.springframework.stereotype.Component;
- @Component
- public class Car {
- public Car() {
- System.out.println("creating the Car bean "+this);
- }
- }
package com.kb.componentscan_annotationconfig; import org.springframework.stereotype.Component; @Component public class Car { public Car() { System.out.println("creating the Car bean "+this); } }
Address.java
- package com.kb.componentscan_annotationconfig;
- import org.springframework.stereotype.Component;
- @Component
- public class Address {
- public Address() {
- System.out.println("creating the Address bean "+this);
- }
- }
package com.kb.componentscan_annotationconfig; import org.springframework.stereotype.Component; @Component public class Address { public Address() { System.out.println("creating the Address bean "+this); } }
Now our beans.xml will have only context:annotation-config element as below
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <context:annotation-config/>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config/> </beans>
Run the client and see the output as below
No output – no beans are loaded no autowiring why?
Because
Yes it never works for the beans which are not registered with spring.
Now replace
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <context:component-scan base-package="com.kb.componentscan_annotationconfig"></context:component-scan>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.kb.componentscan_annotationconfig"></context:component-scan> </beans>
Output
Now this has done autodiscovery. And it also does
Hence the above output.
Now what if we make our beans.xml as below
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <context:annotation-config/>
- <context:component-scan base-package="com.kb.componentscan_annotationconfig"></context:component-scan>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config/> <context:component-scan base-package="com.kb.componentscan_annotationconfig"></context:component-scan> </beans>
Will the duplicate beans gets registered with the Spring ?
No chance, same above output will come.
This is because both
Which one to consider ?
If I have person who is too strong and one is not that strong – whom we choose ?
Yes Spring is also intelligently choose
Which is more stronger(means does what context:annotation-config does + registering beans) than context:annotation-config.
This is how we can say the difference between
great info in here…love it.
Hi Karibasappa,
Getting good knowledge by reading your articles 🙂
Thanks,
Prem
Thank you Prem !!