Solution of Spring Application Throwing NoUniqueBeanDefinitionException Exception

  • 2021-09-24 22:12:07
  • OfStack

Preface to the table of contents
Solutions

Preface

When developing an Spring application, we may accidentally inject two Bean of the same type, such as a class that implements two Service interfaces. The sample pseudo-code is as follows:


interface SampleService {
  String getName();
}

class ServiceA implements SampleService{
   String getName(){
     return "john";
   }
}
class ServiceB implements SampleService{
   String getName(){
     return "wonder";
   }
}

At this time, we use SampleService interface to inject


@Autowired
SampleService sampleService;

After starting the application, Spring will elegantly prompt the following error:

Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.john.primary.SampleService' available: expected single matching bean but found 2: ServiceA,ServiceB

But we don't want to report an error and want to get one of the Bean. What should we do at this time?

Solutions

Since we include two Bean of the same type, generally speaking, we only need to not inject one Bean. What if we want to keep these two Bean of the same type, but want SampleService to be injected normally?

If we are configuring Bean with Xml from the earlier Spring, we can solve the problem in the following two ways:

1. Then we can add autowire-candidate= "false" to one of the Bean configurations


<bean id="serviceA" class="com.john.primary.ServiceA" />
<bean id="serviceB" class="com.john.primary.ServiceB" autowire-candidate="false" />

2. Or add primary= "true" to one of the Bean configurations:


<bean id="serviceA" class="com.john.primary.ServiceA" primary="true"/>
<bean id="serviceB" class="com.john.primary.ServiceB" />

3. Adopt javax. annotation. Priority annotation

This approach requires us to add dependencyComparator to BeanFactory, and the sample code is as follows:


DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)context.getBeanFactory();
//@Priority Annotation comparison 
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
SampleService sampleService= context.getBean(SampleService.class);

4. Implement the annotation Order or implement the org. springframework. core. Ordered interface


public class ServiceA implements SampleService,Ordered {

  @Override
  public int getOrder() {
     return 0;
  }

  @Override
  public String toString() {
     return "ServiceA{}";
  }
}

This approach requires us to override the getPriority method of AnnotationAwareOrderComparator, with the following sample code:


public class PriorityOrderComparator extends AnnotationAwareOrderComparator {
  /**
   * Shared default instance of {@code PriorityOrderComparator}.
   */
  public static final PriorityOrderComparator INSTANCE = new PriorityOrderComparator();

  @Override
  public Integer getPriority(Object obj) {
         // Get first Priority
      Integer order = super.getPriority(obj);
      if(order == null)
        // Get Order Annotations or Ordered Interface return value 
        return  super.findOrder(obj);
      return  order;
  }
}

We can also use the popular annotation method, which is also mentioned in Spring document:

Because autowiring by type may lead to multiple candidates, it is often necessary to have more control over the selection process. One way to accomplish this is with Spring's @Primary annotation. @Primary indicates that a particular bean should be given preference when multiple beans are candidates to be autowired to a single-valued dependency. If exactly one primary bean exists among the candidates, it becomes the autowired value.

You can use the following methods:

1. @ Primary notes:

This annotation can be annotated on a class or a method, as shown in the following example:


@Primary
@Component
class ServiceA implements SampleService{
  String getName(){
    return "john";
  }
}

Annotations on methods with @ Bean annotations:


@Bean
@Primary
SampleService sampleService(){
  return new ServiceA();
}

2. Solution 3 or 4 in the Xml configuration is still adopted, but AnnotationAwareOrderComparator needs to be re-extended if Solution 4 is adopted

The above is the Spring application throws NoUniqueBeanDefinitionException exception solution detailed content, more about Spring throws exception solution information please pay attention to this site other related articles!


Related articles: