Tuesday, 19 April 2016

Difference between component-scan and annotation-config in Spring

To get the difference between annotation-config element and component-scan element you have to know about two terms -

  • Autowiring of beans
  • Autodiscovery of beans

Autowiring of beans

When you use only XML configuration for registering your beans and defining dependencies then you need to configure everything manually in your XML.

As Example If you have 2 classes PayServiceImpl and CashPayment where PayServiceImpl uses object of CashPayment class then in your spring configuration you will have something like this -

<?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-4.0.xsd">
 
 <!-- defining CashPayment bean -->
  <bean id="cashPaymentBean" class="org.netjs.exp.Spring_Example.CashPayment" />
 
  <!-- Defining PayServiceImpl bean and injecting payment bean -->
  <bean id="payServiceBean" class="org.netjs.exp.Spring_Example.PayServiceImpl">
      <property name="payment" ref="cashPaymentBean" />
  </bean>
</beans>

If you use autowiring then also you have two options -

In case you use annotations, you need to activate annotations and you have to add <context:annotation-config /> in your XML file.

With that if we take the same example as above the configuration will be like this -

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
 
   <context:annotation-config/>  
 
   <bean id="cashPaymentBean" class="org.netjs.prog.CashPayment" />
 
   <!-- Defining PayServiceImpl bean and injecting payment bean -->
   <bean id="paymentBean" class="org.netjs.prog.PayServiceImpl">
      <!-- <property name="payment" ref="cashPaymentBean" /> -->
   </bean> 
</beans>

Note the inclusion of <context:annotation-config /> and exclusion of <property name="payment" ref="cashPaymentBean" /> (it is commented).

You don't need property as the dependency will be injected automatically but you need one more change for that in your PayServiceImpl class. You need to use @Autowired annotation to autowire the payment property.

import org.springframework.beans.factory.annotation.Autowired;
public class PayServiceImpl implements IPayService {
    private IPayment payment;

    public void performPayment() {
        // calling method on Ipayment implementing class
        payment.executePayment();
    }
    
    public IPayment getPayment() {
        return payment;
    }

    @Autowired
    public void setPayment(IPayment payment) {
        this.payment = payment;
    }
}

Here points to note are -

  • You have to include <context:annotation-config /> in your XML for autowiring using annotation to work.
  • You don't need to manually write the dependencies with property or constructor-arg tag and ref attribute.
  • You still have to define all your beans because <context:annotation-config /> only works on beans registered within the application context. That's where enters the auto discovery of beans.

Autodiscovery of beans

With autowiring you can simplify you XML configuration to the extent that you don't need to provide the dependencies. But auto-discovery goes one step further and eliminates the need to add the <bean> tag altogether in your xml.

That can be done using <context:component-scan> element and pointing the base package, it configures Spring to automatically discover beans and declare them for you.

This removes the need to use XML to perform bean registration and for most of the classes you don’t need <bean> element to declare and wire beans.

Annotations used for auto-discovery

Using componentscan element is half of the picture, you need to annotate your classes which needs to be auto-discovered with one of these annotations @Component, @Service, @Controller, @Repository

  • @Component - It is a generic stereotype for any Spring-managed component.
  • @Service - More suitable for a class used as a service.
  • @Repository - This annotation is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO).
  • @Controller - More suitable for a class used in presentation layer as a controller.
  • Any custom annotation that is itself annotated with @Component.

As Exp. If you have 2 classes PayServiceImpl and CashPayment where PayServiceImpl uses object of CashPayment class then you configuration will look like this -

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
 
    <context:component-scan base-package="org.netjs.prog" />  
 
</beans>

PayServiceImpl class

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
public class PayServiceImpl implements IPayService {
 @Autowired
 private IPayment payment;

 public void performPayment() {
  // calling method on Ipayment implementing class
  payment.executePayment();
 }
 
 public IPayment getPayment() {
  return payment;
 }
 
 
 public void setPayment(IPayment payment) {
  this.payment = payment;
 }
}

Here note that the class is annotated with @Service annotation, that's how it is made sure that this class is discovered while a component scan is done. Also note that the dependency to the payment is annotated with the annotation @Autowired. That's how Spring will detect and automatically do the dependency injection.

Class CashPayment

import org.springframework.stereotype.Component;

@Component
public class CashPayment implements IPayment{
 public void executePayment() {
  System.out.println("Perform Cash Payment - "); 
 }
}

Note here that - The use of <context:component-scan> implicitly enables the functionality of <context:annotation-config>. There is usually no need to include the <context:annotation-config> element when using <context:component-scan>. So <context:component-scan> will do everything which <context:annotation-config> does and it provides the added functionality of auto-discovery of beans.

That's all for this topic Difference between component-scan and annotation-config in Spring. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Autodiscovery of bean using componenent-scan in Spring
  2. Autowiring using annotations in Spring
  3. How to inject prototype scoped bean in singleton bean
  4. Different bean scopes in Spring
  5. Setter-based dependency injection in Spring

You may also like -

>>>Go to Spring tutorial page

No comments:

Post a Comment