Wednesday, January 1, 2020

Excluding Bean From Autowiring in Spring

You can exclude a bean from autowiring in Spring framework per-bean basis. If you are using Spring XML configuration then you can exclude a bean from autowiring by setting the autowire-candidate attribute of the <bean/> element to false. That way container makes that specific bean definition unavailable to the autowiring infrastructure.

Excluding bean using autowire-candidate example

Here we have a class PayServiceImpl which has a field payment of type IPayment which we have to autowire. Also there are two classes CashPayment and CardPayment which implements IPayment interface.

IpayService interface

public interface IPayService{
 void performPayment();
}

PayServiceImpl class

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

public class PayServiceImpl implements IPayService{
 @Autowired
 private IPayment payment;
 
 public void setPayment(IPayment payment) {
  this.payment = payment;
 }

 public void performPayment() {
  System.out.println("performPayment Method called");
  payment.executePayment();
 }
}

Here note the @Autowired annotation on payment field.

Interface Ipayment

public interface IPayment{
 void executePayment();
}

CashPayment class

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

CardPayment class

public class CardPayment implements IPayment{
 public void executePayment() {
  System.out.println("Perform Card Payment "); 
 }
}

XML Configuration

<?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
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
    <context:annotation-config/>
     
    <bean id="cash" class="org.netjs.exp.Spring_Example.CashPayment" />
    <bean id="card" class="org.netjs.exp.Spring_Example.CardPayment" />
   
    <bean id="payServiceBean" class="org.netjs.exp.Spring_Example.PayServiceImpl">
    </bean>
  
</beans>

Here we have defined two beans of type Ipayment CashPayment and CardPayment. This will result in BeanCreationException as container won’t be able to decide which on of the two inject in PayServiceImpl class.

You can check that by running the code using the following Java class.

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main( String[] args ){
       AbstractApplicationContext context = new ClassPathXmlApplicationContext
           ("appcontext.xml");
  
       IPayService payBean = (IPayService)context.getBean("payServiceBean");
     
       payBean.performPayment();

       context.registerShutdownHook();
 } 
}

Output

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'payServiceBean': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.netjs.exp.Spring_Example.IPayment org.netjs.exp.Spring_Example.PayServiceImpl.payment; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.netjs.exp.Spring_Example.IPayment] is defined: expected single matching bean but found 2: cash,card

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.netjs.exp.Spring_Example.IPayment] is defined: expected single matching bean but found 2: cash,card

If you set autowire-candidate attribute as false for one of the bean then the problem will be resolved.

<bean id="cash" class="org.netjs.exp.Spring_Example.CashPayment" autowire-candidate="false" />

With this change if you run the code, card bean will be injected.

Output

performPayment Method called
Perform Card Payment 

Resolving conflict with annotations

If you want to use annotations to resolve conflict in this type of situation when you have more than one bean defined of the same type. Then you have two options.

  1. @Qualifier annotation.
  2. @Inject and @Named annotation

Using @Qualifier annotation example

In the example used above where you have two beans CardPayment and CashPayment of the same type, in order 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 in the PayServiceImpl class.

PayServiceImpl.java

public class PayServiceImpl implements IPayService{
 @Autowired
 @Qualifier("cash")
 private IPayment payment;
 
 public void setPayment(IPayment payment) {
  this.payment = payment;
 }

 public void performPayment() {
  System.out.println("performPayment Method called");
  payment.executePayment();
 }
}

Now even if you don’t set autowire-candidate as false for any of the bean that’s ok as @Qualifier annotation will resolve the conflict.

<bean id="cash" class="org.netjs.exp.Spring_Example.CashPayment" />
<bean id="card" class="org.netjs.exp.Spring_Example.CardPayment" />

Using @Inject and @Named annotations

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("cash")
 private IPayment payment;
 
 public void setPayment(IPayment payment) {
  this.payment = payment;
 }


 public void performPayment() {
  System.out.println("performPayment Method called");
  payment.executePayment();
 }
}

Note that you will need to import javax.inject jar in order to use these annotations. In Maven you can do it by adding the following dependency.

  <dependency>
      <groupId>javax.inject</groupId>
      <artifactId>javax.inject</artifactId>
      <version>1</version>
  </dependency>

Recommendations for learning

  1. Spring Framework Master Class Course
  2. Spring & Hibernate for Beginners (Includes Spring Boot)
  3. Java In-Depth: Become a Complete Java Engineer!
  4. Complete Python Bootcamp Course
  5. React - The Complete Guide Course

That's all for this topic Excluding Bean From Autowiring in Spring. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Autowiring Using XML Configuration in Spring
  2. Autowiring Using Annotations in Spring
  3. Autodiscovery of Bean Using component-scan in Spring
  4. @Resource Annotation in Spring Autowiring
  5. How to Inject Null And Empty String Values in Spring

You may also like-

  1. Using depends-on Attribute in Spring
  2. Bean Definition Inheritance in Spring
  3. Select Query Using JDBCTemplate in Spring Framework
  4. String charAt() And substring() Methods in Java
  5. PermGen Space Removal in Java 8
  6. Nested class and Inner class in Java
  7. Java Multi-Threading Interview Questions
  8. Invoking Getters And Setters Using Reflection - Java Program