Saturday 5 April 2014

Spring : context:component-scan vs context:annotation-config

Whats the difference between component-scan and annotation-config

  • <context:annotation-config/>  -   Looks for @Autowired and JSR annotation, It does not identify the @component, @configuration annotations.  It just autowires existing beans
  • whereas <context:component-scan  base-package="org.first" />  Does recoginize @Autowired, @component and other annotations also.
  • <context:component-scan> also does  <context:annotation-config/>  and also scans packages to find registeredbeans

Example  1 :  Let's define the classes in beans.xml and also annotate with @Component and @Autowired

package org.first;
@Component
public class FirstServiceImpl implements FirstService{
    public Name userName;

    public FirstServiceImpl(){
        System.out.println("new FirstServiceImpl()");
    }

    @Autowired
    public void setUserName(final Name userName){
        System.out.println("setUserName(final Name userName)");
        this.userName = userName;
    }
//getters, setters, other constructors
}

package org.first;
@Component
public class Name{
    String name = "new";

    public Name(){
        super();
        System.out.println("new Name()");
    }
   //getters, setters, other constructors
}

beans.xml

<beans><!-- Add Namesapece here -->
    <bean name="userName" class="org.first.Name">
        <property name="name" value="Vidhya"></property>
    </bean>

    <bean name="firstService" class="org.first.FirstServiceImpl">
        <property name="userName" ref="userName"></property>
    </bean>
</beans>


OUTPUT : This will instantiate the userName and firstService classes, because both classes are defined in the xml

new Name()
new FirstServiceImpl()
setUserName(final Name userName)



Example  2 :  Lets try to use <context-annotation-config> :  


package org.first;
@Component
public class FirstServiceImpl implements FirstService{
    public Name userName;
    public FirstServiceImpl(){
        System.out.println("new FirstServiceImpl()");
    }

    @Autowired
    public void setUserName(final Name userName){
        System.out.println("setUserName(final Name userName)");
        this.userName = userName;
    }
//getters, setters, other constructors
}

package org.first;
public class Name{
    String name = "new";

    public Name(){
        super();
        System.out.println("new Name()");
    }
   //getters, setters, other constructors
}
beans.xml
 <beans><!-- Add Namesapece here -->
    <context:annotation-config/>
</beans>

OUTPUT : This will NOT do anything. NO OUTPUT. Why? The annotation-config cannot know about the beans unless defined. 

How to fix this? We need to add bean definitions. Lets add the bean definitions in the beans.xml



Example  3 :  Lets use <context-annotation-config> and bring back the bean definitions.


beans.xml
 <beans><!-- Add Namesapece here -->
    <context:annotation-config/>

    <bean name="userName" class="org.first.Name">
        <property name="name" value="Vidhya"></property>
    </bean>

    <bean name="firstService" class="org.first.FirstServiceImpl">
        <property name="userName" ref="userName"></property>
    </bean>
</beans>

OUTPUT : This will instantiate the userName and firstService classes, because both classes are defined in the xml

new Name()
new FirstServiceImpl()
setUserName(final Name userName)

Example  4 :  So, what's the use of annotation-config? We saw that annotation-config cannot load @component, Now lets see if it can autowire, with same class as in Example 2.


beans.xml
 <beans><!-- Add Namesapece here -->
    <context:annotation-config/>

    <bean name="userName" class="org.first.Name">
        <property name="name" value="Vidhya"></property>
    </bean>

    <bean name="firstService" class="org.first.FirstServiceImpl">
        <property name="userName" ref="userName"></property>
    </bean>
</beans>


OUTPUT : 

new Name() new FirstServiceImpl() setUserName(final Name userName)
Looks like annotation-config can autowire, but cannot instantiate @Component


Example  5 :  Lets use <context:component-scan> now. As per definition, it can read all@component classes and also autowire. We will check that

package org.first;
@Component
public class FirstServiceImpl implements FirstService{
    public Name userName;

    public FirstServiceImpl(){
        System.out.println("new FirstServiceImpl()");
    }

    @Autowired
    public void setUserName(final Name userName){
        System.out.println("setUserName(final Name userName)");
        this.userName = userName;
    }
//getters, setters, other constructors
}

package org.first;
@Component
public class Name{
    String name = "new";

    public Name(){
        super();
        System.out.println("new Name()");
    }
   //getters, setters, other constructors
}
beans.xml
 <beans><!-- Add Namespace here -->
     <context:component-scan base-package="org.first" />
</beans>

OUTPUT : There you go.. Now we achieve with single line in beans.xml, which all @Component and @Autowired annotations.
new FirstServiceImpl()
new Name()
setUserName(final Name userName)

SUMMARY:

1. <context:component-scan> is one stop solution for @Autowired and @Component 
2.<context:annotation-config> can only do @Autowired.
3. I am readying the annotation-config is very useful in the web context with DispatcherServlet. But need to try that. Probably will write about it later when I try it.

References

http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch04s11.html
http://www.tutorialspoint.com/spring/spring_annotation_based_configuration.htm
http://stackoverflow.com/questions/7414794/difference-between-contextannotation-config-vs-contextcomponent-scan

2 comments: