Saturday, January 2, 2021

Autowiring in Spring Using @Autowired and @Inject Annotations

Though autowiring of the beans can be done using XML configuration for autowiring but Spring goes one step further and provides autowiring using annotations which leads to shorter and more concise configuration.

Broadly Spring provides two ways to annotate beans for autowiring-

  • Using @Autowired annotation- It is a spring specific annotation.
  • Using @Inject annotation- It is provided by JSR-330 (Dependency Injection for Java) annotations contained in the javax.inject package. Spring supports this annotation.

In this post we'll see Spring autowiring examples using both @Autowired and @Inject annotations.


Configuration required for autowiring using annotation

To enable autowiring using annotation in Spring, you have to register 'AutowiredAnnotationBeanPostProcessor' class.

  • You can directly provide this class in xml config-
    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
    
  • You can include the <context:annotation-config/> tag in an XML-based Spring configuration (notice the inclusion of the context namespace in XML). This is the preferred way.
    <?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.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
      <context:annotation-config/>
    </beans>
    

    By using <context:annotation-config/> tag following post-processors are implicitly registered AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor and RequiredAnnotationBeanPostProcessor.

  • You can include the <context:component-scan/> tag.

Refer Using component-scan in Spring to Automatically Discover Bean to see why <context:component-scan/> should be used instead of <context:annotation-config/>

Autowiring in Spring using @Autowired annotation

Note that @Autowired annotation can be applied on-

  • setter method
  • constructor
  • field
Here we'll see example for all of these options.

Spring @Autowired annotation on setter

When @Autowired annotation is used on a setter, it is equivalent to autowiring="byType" in autowiring using configuration file.

Here we have a class PayServiceImpl which has a field payment of type IPayment which we have to autowire. Also class CashPayment which implements IPayment interface.

interface IPayService

public interface IPayService {
 void performPayment();
}

PayServiceImpl class

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 note the @Autowired annotation on setPayment() method.

Interface IPayment

public interface IPayment {
 void executePayment();
}

CashPayment class

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

XML configuration file

<?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>

Here note the inclusion of <context:annotation-config/> tag which is required for autowired annotation. Also note that ref for cashPaymentBean is no longer required as a property in paymentBean (it is commented in the config). It will be injected automatically now because of the @Autowired annotation.

You can use the following code to run this program -

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
  public static void main( String[] args ){  
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext
       ("appcontext.xml");
    // Getting PayServiceImpl 
    IPayService bean = (IPayService) context.getBean("paymentBean");
    bean.performPayment();
    context.close();
  }
}

Output

Perform Cash Payment-

@Autowired annotation on field

When @Autowired annotation is used on a property, it is equivalent to autowiring="byType" when autowiring is done using configuration file.

In this case PayServiceImpl will change to have @Autowired annotation on the field. When using @Autowired with field you don't even need the setter method for that field.

PayServiceImpl class

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;
 }*/
}

Rest of the things remain the same as used in the example for @Autowired on setter.

@Autowired annotation on constructor

When @Autowired annotation is used on a bean's constructor, it is equivalent to autowiring="constructor" when autowiring is done using configuration file.

In this case PayServiceImpl will change to have @Autowired annotation on the constructor of the class. When using @Autowired on constructor you don't even need the setter method for that field.

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

public class PayServiceImpl implements IPayService {
 
 private IPayment payment;
 // Constructor 
 @Autowired
 PayServiceImpl(IPayment payment){
  this.payment = 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;
 }*/
}

Rest of the things remain the same as used in the example for @Autowired on setter.

@Autowired annotation on arbitrary methods

You can also apply the annotation to methods with arbitrary names and/or multiple arguments, Example as taken from Spring reference doc

public class MovieRecommender {
  private MovieCatalog movieCatalog;
  private CustomerPreferenceDao customerPreferenceDao;
  @Autowired
 public void prepare(MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) {
   this.movieCatalog = movieCatalog;
   this.customerPreferenceDao = customerPreferenceDao;
 }
 // ...
}

@Autowired annotation with required=false

The default behavior for the annotation is to treat annotated methods, constructors, and fields as indicating required dependencies. Thus the autowiring fails whenever zero candidate beans are available. You can make the autowiring optional to avoid such errors, this can be done by using required="false" with the @Autowired annotation.

@Autowired(required=false)
private IPayment payment;

Conflict resolution using Spring @Qualifier annotation

What if there are more than one bean in the configuration file whose type is compatible with the autowired property. In that case Spring won't be able to decide which bean to use, it will throw an exception instead.

In the above application we had used only one implementation of IPayment, CashPayment so there was no problem in automatically wiring it. Now suppose we have one more implementation of the IPayment interface, Credit Payment. In that case with the current setup you'll get NoUniqueBeanDefinitionException because Spring won't know which Payment class to wire.

CreditPayment class

public class CreditPayment implements IPayment {
 public void executePayment() {
  System.out.println("Performing credit payment ");
 }
}

Adding CreditPayment definition in config

<bean id="creditPaymentBean" class="org.netjs.prog.CreditPayment" />

Now if you run the code you will get NoUniqueBeanDefinitionException-

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'paymentBean': 
Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: 
Could not autowire field: private org.netjs.prog.IPayment org.netjs.prog.PayServiceImpl.payment; 
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
No qualifying bean of type [org.netjs.prog.IPayment] is defined: expected single matching bean but found 2: 
cashPaymentBean,creditPaymentBean
 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)

In this kind of scenario, to avoid ambiguity you can use @Qualifier annotation to qualify the bean. Suppose you want to inject cashPaymentBean then you can qualify it by passing bean name with the qualifier annotation.

@Qualifier example to avoid NoUniqueBeanDefinitionException error

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class PayServiceImpl implements IPayService {
 @Autowired
 @Qualifier("cashPaymentBean")
 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;
 }*/
}

Using JSR-330 @Inject annotation

Instead of @Autowired, @javax.inject.Inject annotation can be used for autowiring in Spring. @Inject annotation is part of the standard JSR-330: Dependency injection for Java. So, if you don't want Spring specific annotations and want to go with standard annotation then use @Inject.

As with @Autowired, it is possible to use @Inject at the class-level, field-level, method-level and constructor-argument level.

Note one thing though. @Inject has no 'required' attribute as provided with @Autowired, so @Inject annotated dependencies can't be optional, an exception will be thrown if they are not fulfilled.

@Named annotation

If you would like to use a qualified name for the dependency that should be injected, instead of @Qualifier you can use @Named annotation which is again part of the standard JSR-330: Dependency injection for Java.

Spring autowiring example with @Inject and @Named annotations

Let's take the same case where we have two payment classes CashPayment and CreditPayment. If you want to make sure that CashPayment bean is the one which is injected then using @Inject and @Named annotations the PayServiceImpl class will look like -

import javax.inject.Inject;
import javax.inject.Named;

public class PayServiceImpl implements IPayService {
 @Inject
 @Named("cashPaymentBean")
 private IPayment payment;

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

Note here that @Inject annotation is used with the setter.

Configuration file for the example

<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" />
 
 <bean id="creditPaymentBean" class="org.netjs.prog.CreditPayment" />
 
  <!-- Defining PayServiceImpl bean and injecting payment bean -->
  <bean id="paymentBean" class="org.netjs.prog.PayServiceImpl">
  </bean>
</beans>

Are annotations better than XML for configuring Spring?

According to the Spring reference doc-

The introduction of annotation-based configurations raised the question of whether this approach is 'better' than XML. The short answer is it depends. The long answer is that each approach has its pros and cons, and usually it is up to the developer to decide which strategy suits them better. Due to the way they are defined, annotations provide a lot of context in their declaration, leading to shorter and more concise configuration. However, XML excels at wiring up components without touching their source code or recompiling them. Some developers prefer having the wiring close to the source while others argue that annotated classes are no longer POJOs and, furthermore, that the configuration becomes decentralized and harder to control.

That's all for this topic Autowiring in Spring Using @Autowired and @Inject Annotations. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Autowiring in Spring Using XML Configuration
  2. Dependency Injection in Spring Framework
  3. How to Read Properties File in Spring Framework
  4. Difference Between component-scan And annotation-config in Spring
  5. @Resource Annotation in Spring Autowiring

You may also like-

  1. Bean Definition Inheritance in Spring
  2. Spring p-namespace For Shorter XML Configuration
  3. Spring NamedParameterJdbcTemplate Insert, Update And Delete Example
  4. Difference Between throw And throws in Java
  5. How to Sort an ArrayList in Descending Order in Java
  6. LinkedHashMap in Java With Examples
  7. How to Create PDF From XML Using Apache FOP
  8. How to Find Last Modified Date of a File in Java

1 comment:

  1. Good Explanation with good knowledge, keep it up. Thank you very much sir.

    ReplyDelete