Friday, January 6, 2023

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>

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 in Spring Using XML Configuration
  2. Autowiring in Spring Using @Autowired and @Inject Annotations
  3. Benefits, Disadvantages And Limitations of Autowiring in Spring
  4. Spring MessageSource Internationalization (i18n) Support
  5. Spring Object XML Mapping (OXM) JAXB Example

You may also like-

  1. Spring depends-on Attribute and @DependsOn With Examples
  2. Bean Definition Inheritance in Spring
  3. Spring Batch Processing Using JDBCTemplate batchUpdate() Method
  4. Spring MVC @PathVariable Example - Creating Dynamic URL
  5. Java String substring() Method - Getting Substring
  6. PermGen Space Removal in Java 8
  7. Java Nested Class And Inner Class
  8. Java Multithreading Interview Questions And Answers

No comments:

Post a Comment