Monday, December 28, 2015

Spring - Spring MVC: Difference between context:annotation-config vs context:component-scan

1) First big difference between both tags is that <context:annotation-config> is used to activate applied annotations in already registered beans in application context. Note that it simply does not matter whether bean was registered by which mechanism e.g. using<context:component-scan> or it was defined in application-context.xml file itself.

2) Second difference is driven from first difference itself. It registers the beans defined in config file into context + it also scans the annotations inside beans and activate them. So<context:component-scan> does what <context:annotation-config> does, but additionally it scan the packages and register the beans in application context.

<context:annotation-config> = Scanning and activating annotations in “already registered beans”.

<context:component-scan> = Bean Registration + Scanning and activating annotations

We have already learned few things in Spring MVC in previous posts. In those tutorials, I did use tags like <context:annotation-config> or <context:component-scan>, but I didn’t explained much in detail about these tags. I am writing this post, specifically to list down the difference between tags <context:annotation-config> and <context:component-scan> so that when you use them in future, you will know, what exactly are you doing.
1) First big difference between both tags is that <context:annotation-config> is used to activate applied annotations in already registered beans in application context. Note that it simply does not matter whether bean was registered by which mechanism e.g. using<context:component-scan> or it was defined in application-context.xml file itself.
2) Second difference is driven from first difference itself. It does register the beans in context + it also scans the annotations inside beans and activate them. So <context:component-scan&gt; does what <context:annotation-config> does, but additionally it scan the packages and register the beans in application context.

Example of <context:annotation-config> vs <context:component-scan> uses

I will elaborate both tags in detail with some examples which will make more sense to us. For keeping the example to simple, I am creating just 3 beans, and I will try to configure them in configuration file in various ways, then we will see the difference between various configurations in console where output will get printed.
For reference, below are 3 beans. BeanA has reference to BeanB and BeanC additionally.
packagecom.howtodoinjava.beans;

importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Component;

@SuppressWarnings("unused")
@Component
publicclassBeanA {
     
    privateBeanB beanB;
    privateBeanC beanC;
     
    publicBeanA(){
        System.out.println("Creating bean Bean A");
    }

    @Autowired
    Public void setBeanB(BeanB beanB) {
        System.out.println("Setting bean reference for BeanB");
        this.beanB = beanB;
    }

    @Autowired
    publicvoidsetBeanC(BeanC beanC) {
        System.out.println("Setting bean reference for BeanC");
        this.beanC = beanC;
    }
}

//Bean B

packagecom.howtodoinjava.beans;

importorg.springframework.stereotype.Component;

@Component
publicclassBeanB {
    publicBeanB(){
        System.out.println("Creating bean BeanB");
    }
}

//Bean C

packagecom.howtodoinjava.beans;

importorg.springframework.stereotype.Component;

@Component
publicclassBeanC {
    publicBeanC(){
        System.out.println("Creating bean BeanC");
    }
}
BeanDemo class is used to load and initialize the application context.
packagecom.howtodoinjava.test;

importorg.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;

publicclassBeanDemo {
    publicstaticvoidmain(String[] args) {
        ApplicationContext context = newClassPathXmlApplicationContext("classpath:beans.xml");
    }
}
Now let’s start writing the configuration file "beans.xml" with variations. I will be omitting the schema declarations in below examples, to keep focus on configuration itself.

a) Define only bean tags

<beanid="beanA"class="com.howtodoinjava.beans.BeanA"></bean>
<beanid="beanB"class="com.howtodoinjava.beans.BeanB"></bean>
<beanid="beanC"class="com.howtodoinjava.beans.BeanC"></bean>

Output:

Creating bean BeanA
Creating bean BeanB
Creating bean BeanC
In this case, all 3 beans are created and no dependency in injected in BeanA because we didn’t used any property/ref attributes.

b) Define bean tags and property ref attributes

<beanid="beanA"class="com.howtodoinjava.beans.BeanA">
    <propertyname="beanB"ref="beanB"></property>
    <propertyname="beanC"ref="beanC"></property>
</bean>
<beanid="beanB"class="com.howtodoinjava.beans.BeanB"></bean>
<beanid="beanC"class="com.howtodoinjava.beans.BeanC"></bean>

Output:

Creating bean BeanA
Creating bean BeanB
Creating bean BeanC
Setting bean reference for BeanB
Setting bean reference for BeanC
Now the beans are created and injected as well. No wonder.

c) Using only <context:annotation-config />

<context:annotation-config/>

//No Output
As I told already, <context:annotation-config /> activate the annotations only on beans which have already been discovered and registered. Here, we have not discovered any bean so nothing happened.

d) Using <context:annotation-config /> with bean declarations

<context:annotation-config/>
<beanid="beanA"class="com.howtodoinjava.beans.BeanA"></bean>
<beanid="beanB"class="com.howtodoinjava.beans.BeanB"></bean>
<beanid="beanC"class="com.howtodoinjava.beans.BeanC"></bean>

Output:

Creating bean BeanA
Creating bean BeanB
Setting bean reference for BeanB
Creating bean BeanC
Setting bean reference for BeanC
In above configuration, we have discovered the beans using <bean> tags. Now when we use<context:annotation-config />, it simply activates @Autowired annotation and bean injection inside BeanA happens.

e) Using only <context:component-scan />

<context:component-scanbase-package="com.howtodoinjava.beans"/>

Output:

Creating bean BeanA
Creating bean BeanB
Setting bean reference for BeanB
Creating bean BeanC
Setting bean reference for BeanC
Above configuration does both things as I mentioned earlier in start of post. It does the bean discovery (searches for @Component annotation in base package) and then activates the additional annotations (e.g. Autowired).

f) Using both <context:component-scan /> and <context:annotation-config />


<context:annotation-config/>
<context:component-scanbase-package="com.howtodoinjava.beans"/>
<beanid="beanA"class="com.howtodoinjava.beans.BeanA"></bean>
<beanid="beanB"class="com.howtodoinjava.beans.BeanB"></bean>
<beanid="beanC"class="com.howtodoinjava.beans.BeanC"></bean>

Output:

Creating bean BeanA
Creating bean BeanB
Setting bean reference for BeanB
Creating bean BeanC
Setting bean reference for BeanC

No comments:

Post a Comment