在Spring中,@Qualifier的意思是,Bean有资格自动装配上到一个字段。请参见以下情形:
自动装配示例
参见下面的例子,它会自动装配“person” bean 到 customer 的 person 属性。
package com.gp6.autoAssemblyBean.qualifier;
import org.springframework.beans.factory.annotation.Autowired;
public class Customer {
@Autowired
private Person person;
private int type;
private String action;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}
但是,两个类似的 bean “com.gp6.autoAssemblyBean.qualifier.Person” 在 bean 配置文件中声明。Spring会知道哪个person bean应当自动装配?
<!-- 直接包含 AutowiredAnnotationBeanPostProcessor -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="CustomerBean" class="com.gp6.autoAssemblyBean.qualifier.Customer">
<property name="action" value="buy" />
<property name="type" value="1" />
</bean>
<bean id="PersonBean1" class="com.gp6.autoAssemblyBean.qualifier.Person">
<property name="name" value="gp6" />
<property name="address" value="address 123" />
<property name="age" value="28" />
</bean>
<bean id="PersonBean2" class="com.gp6.autoAssemblyBean.qualifier.Person">
<property name="name" value="gp6" />
<property name="address" value="address 123" />
<property name="age" value="28" />
</bean>
</beans>
当你运行上面的例子,它产生以下异常:
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CustomerBean': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.gp6.autoAssemblyBean.qualifier.Person com.gp6.autoAssemblyBean.qualifier.Customer.person; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.gp6.autoAssemblyBean.qualifier.Person] is defined: expected single matching bean but found 2: [PersonBean1, PersonBean2]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.gp6.autoAssemblyBean.qualifier.Test.main(Test.java:8)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.gp6.autoAssemblyBean.qualifier.Person com.gp6.autoAssemblyBean.qualifier.Customer.person; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.gp6.autoAssemblyBean.qualifier.Person] is defined: expected single matching bean but found 2: [PersonBean1, PersonBean2]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:506)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:284)
... 13 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.gp6.autoAssemblyBean.qualifier.Person] is defined: expected single matching bean but found 2: [PersonBean1, PersonBean2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:800)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
... 15 more
@Qualifier示例
要解决上述问题,需要使用 @Quanlifier 告诉Spring哪些bean应当自动装配。
package com.gp6.autoAssemblyBean.qualifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Customer {
@Autowired
@Qualifier("PersonBean1")
private Person person;
private int type;
private String action;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}