We use Spring’s @Autowired
annotation to inject dependencies. If there are more than one bean defined of the same type then based on the member variable name the bean is resolved but what if we use a name which doesn’t match with the bean ID. In such cases, we can rely on Spring’s @Qualifier
annotation which can help resolve the auto-wiring conflicts. It may be used on a field or parameter. As the name suggests it is used as a qualifier for candidate beans when auto-wiring. We will also see how it can be used be to annotate a custom annotations that can then in turn be used as qualifiers.
We will use one bean type to create several bean definitions.
BeanA:
package com.javarticles.spring; public class BeanA { private String name; public BeanA(){} public BeanA(String name){ this.name = name; } public String toString() { return name == null ? super.toString() : "BeanA(" + name + ")"; } }
Below is a custom annotation annotated with @Qualifier
. The default bean ID is ‘A4’. One can use it in place of @Qualifier
.
QualifierA4:
package com.javarticles.spring; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import org.springframework.beans.factory.annotation.Qualifier; @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface QualifierA4 { String value() default "A4"; }
We will now define beans in Config
class. You will see several flavors of BeanA
.
- We define couple of beans without any qualifier, with bean IDs
beanA
andbeanA0
- Next bean is another instance of
BeanA
but qualified with@Qualifier
beanA2()
andbeanA3()
are qualified with values ‘A2’ and ‘A3’.beanA4()
is qualified with custom qualifierQualifierA4
Config:
package com.javarticles.spring; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class Config { @Bean public BeanA beanA() { return new BeanA(); } @Bean public BeanA beanA0() { return new BeanA("A0"); } @Bean @Qualifier public BeanA beanA1() { return new BeanA("A1"); } @Bean @Qualifier("A2") public BeanA beanA2() { return new BeanA("A2"); } @Bean @Qualifier("A3") public BeanA beanA3() { return new BeanA("A3"); } @Bean @QualifierA4 public BeanA beanA4() { return new BeanA("A4"); } }
In the below class we auto-wire BeanA
type beans. The bean is selected based on either the bean name or the qualifier used. For example, @Qualifier("beanA")
will auto-wire bean returned by Config.beanA()
, the value passed in will be used as the bean ID. Based on the @Qualifier
used it will figure out which bean to inject.
You can also use custom annotation, for example, below will inject beanA4
:
@Autowired @QualifierA4 private BeanA customQualifiedBeanA;
The inner static class InnerConfig
contains all beans auto-wired using @Qualifier
QualifierAnnotationExample:
package com.javarticles.spring; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.stereotype.Component; @Configuration @Import(Config.class) public class QualifierAnnotationExample { @Autowired @Qualifier("beanA") private BeanA beanA; @Autowired @Qualifier("beanA0") private BeanA beanA0; @Autowired @Qualifier private BeanA beanA1; @Autowired @Qualifier("A3") private BeanA beanA3; @Autowired @QualifierA4 private BeanA customQualifiedBeanA; public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( QualifierAnnotationExample.class); try { QualifierAnnotationExample qualifierAnnotationExample = (QualifierAnnotationExample) context .getBean("qualifierAnnotationExample"); System.out.println("BeanA member: " + qualifierAnnotationExample.getBeanA()); System.out.println("BeanA1 member: " + qualifierAnnotationExample.getBeanA1()); System.out.println("Qualified BeanA member: " + qualifierAnnotationExample.getBeanA3()); System.out.println("Custom Qualified BeanA member: " + qualifierAnnotationExample.getCustomQualifiedBeanA()); System.out.println("InnerConfig:\n" + context.getBean("innerConfig")); } finally { context.close(); } } public BeanA getBeanA() { return beanA; } public BeanA getBeanA0() { return beanA0; } public BeanA getBeanA1() { return beanA1; } public BeanA getBeanA3() { return beanA3; } public BeanA getCustomQualifiedBeanA() { return customQualifiedBeanA; } @Component("innerConfig") static class InnerConfig { private BeanA beanA; private BeanA beanA0; private BeanA beanA1; private BeanA beanA2; private BeanA beanA3; private BeanA beanA4; @Autowired public InnerConfig(@Qualifier("beanA") BeanA beanA, @Qualifier("beanA0") BeanA beanA0, @Qualifier BeanA beanA1, @Qualifier("A2") BeanA beanA2, @Qualifier("A3") BeanA beanA3, @QualifierA4 BeanA beanA4) { this.beanA = beanA; this.beanA0 = beanA0; this.beanA1 = beanA1; this.beanA2 = beanA2; this.beanA3 = beanA3; this.beanA4 = beanA4; } public String toString() { return "BeanA(" + beanA + "),\nBeanA0(" + beanA0 + "),\nBeanA1(" + beanA1 + "),\nBeanA2(" + beanA2 + "),\nBeanA3(" + beanA3 + "),\nBeanA4(" + beanA4 + ")"; } } }
Output:
Feb 18, 2016 12:56:00 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh INFO: Refreshing org.spring[email protected]7c3df479: startup date [Thu Feb 18 12:56:00 IST 2016]; root of context hierarchy BeanA member: [email protected] BeanA1 member: BeanA(A1) Qualified BeanA member: BeanA(A3) Custom Qualified BeanA member: BeanA(A4) InnerConfig: BeanA([email protected]), BeanA0(BeanA(A0)), BeanA1(BeanA(A1)), BeanA2(BeanA(A2)), BeanA3(BeanA(A3)), BeanA4(BeanA(A4)) Feb 18, 2016 12:56:00 PM org.springframework.context.annotation.AnnotationConfigApplicationContext doClose INFO: Closing org.spring[email protected]7c3df479: startup date [Thu Feb 18 12:56:00 IST 2016]; root of context hierarchy
Dubious Bean if @Qualifier missing
Below configuration fails with BeanCreationException
as there are multiple implementations found for BeanA
and spring couldn’t figure out which one to inject. There is no @Qualifier
used and the member variable name doesn’t match with any of the bean names.
Here is the error:
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'failAutowiringExample': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.javarticles.spring.BeanA com.javarticles.spring.FailAutowiringExample.dubiousBeanA; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.javarticles.spring.BeanA] is defined: expected single matching bean but found 6: beanA,beanA0,beanA1,beanA2,beanA3,beanA4
FailAutowiringExample:
package com.javarticles.spring; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.javarticles.spring") public class FailAutowiringExample { @Autowired private BeanA dubiousBeanA; public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( FailAutowiringExample.class); try { FailAutowiringExample qualifierAnnotationExample = (FailAutowiringExample) context .getBean("failAutowiringExample"); System.out.println("BeanA member: " + qualifierAnnotationExample.getBeanA()); } finally { context.close(); } } public BeanA getBeanA() { return dubiousBeanA; } }
Output:
Feb 18, 2016 10:41:28 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh INFO: Refreshing org.spring[email protected]7c3df479: startup date [Thu Feb 18 22:41:28 IST 2016]; root of context hierarchy Feb 18, 2016 10:41:28 PM org.springframework.context.annotation.AnnotationConfigApplicationContext refresh WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'failAutowiringExample': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.javarticles.spring.BeanA com.javarticles.spring.FailAutowiringExample.dubiousBeanA; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.javarticles.spring.BeanA] is defined: expected single matching bean but found 6: beanA,beanA0,beanA1,beanA2,beanA3,beanA4 Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'failAutowiringExample': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.javarticles.spring.BeanA com.javarticles.spring.FailAutowiringExample.dubiousBeanA; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.javarticles.spring.BeanA] is defined: expected single matching bean but found 6: beanA,beanA0,beanA1,beanA2,beanA3,beanA4 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) at org.springframework.context.annotation.AnnotationConfigApplicationContext.(AnnotationConfigApplicationContext.java:84) at com.javarticles.spring.FailAutowiringExample.main(FailAutowiringExample.java:16) Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.javarticles.spring.BeanA com.javarticles.spring.FailAutowiringExample.dubiousBeanA; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.javarticles.spring.BeanA] is defined: expected single matching bean but found 6: beanA,beanA0,beanA1,beanA2,beanA3,beanA4 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ... 12 more Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.javarticles.spring.BeanA] is defined: expected single matching bean but found 6: beanA,beanA0,beanA1,beanA2,beanA3,beanA4 at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1126) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545) ... 14 more
Download the source code
This was an example about spring @Qualifier annotation.