当按类型自动装配可能多个bean实例的情况,可以使用Spring的@Qualifier注解缩小范围(或指定唯一),也可以用于指定单独的构造器参数或方法参数。
可用于注解集合类型变量。
比如说按类型装配可能有多个bean的时候,在前一篇的例子中提到,可以使用@Autowired去注解List<>、Set<>这样的数组集合,或者是Map<>这样的键值对,然后可以把同一种类型的bean注册到list或者map当中去。那么在这种情况下使用@Qualifier可以缩小注解的范围,或者可以指定唯一的bean。
也就是说按照刚才的例子,BeanInterface和BeanImplOne、BeanImplTwo,如果我们在类中声明了一个BeanInterface类型的成员变量,我们可以指定用One或者Two哪一个实现类。
当然,它可以用于具体的单独的构造器函数或者是方法的参数。看一下例子:
public class MovieRecommender{
@Autowired
@Qualifier("main")
private MovieCatalog movieCatalog;
}
首先用@Autowired注解,当然,如果有多个这种MovieCatalog的时候,我们可以通过@Qualifier来指定使用main也就是bean的id为main的MovieCatalog的实现类或者是子类。
上边这种情况使用在成员变量上,它也可以用在方法参数中:
public class MovieRecommender{
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(@Qualifier("main")MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao){
this.movieCatalog=movieCatalog;
this.customerPreferenceDao=customerPreferenceDao;
}
//...
}
在这个prepare()方法中,第一个参数MovieCatalog,我们可以指定@Qualifier,那它就是用
MovieCatalog对应bean的id为main的bean的实例。这也是@Qualifier这个注解用的最多的一个场景。
如何在xml文件中来实现这种@Qualifier?
<bean class="example.SimpleMovieCatalog">
<qualifier value="main"/>
</bean>
这就是在xml配置文件中使用@Qualifier。
如果通过名字进行注解注入,主要使用的不是@Autowired(即使在技术上能够通过@Qualifier指定bean的名字,然后再通过@Autowired进行注入),替代方式是使用JSR-250标准中的@Resource注解,它是通过其独特的名称来定义俩识别特定的目标(这是一个与声明的类型是无关的匹配过程)。
因语义差异,集合或Map类型的bean无法通过@Autowired来注入,因为没有类型匹配到这样的bean,为这些bean使用@Resource注解,可以通过唯一名称引用集合或Map的bean。
@Autowired适用于fields(字段)、constructors(构造器)、multi-argument methods(多参数的方法)这些允许在参数级别使用@Qualifier注解缩小范围的情况。
@Resource适用于成员变量、只有一个参数的setter方法,所以在目标是构造器或一个多参数方法时,最好的方式是使用qualifiers。
可以定义自己的qualifier注解并使用。
比如定义一个自己的Qualifier,有个value的变量,当在某个类中去使用自定义的Qualifier,可以达到一样的效果。那通过什么样的方式呢?
就是定义自己的注解的时候,用@Qualifier来注解我们自定义的注解,那么我们自定义的注解就具有了相应的功能。
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre{
String value();
}
public class MovieCatalog{
@Autowired
@Genre("Action")
private MovieCatalog actionCatalog;
private MovieCatalog comedyCatalog;
@Autowired
public void setComedyCatalog(@Genre("Comedy")MovieCatalog comedyCatalog){
this.comedyCatalog=comedyCatalog;
}
//...
}
这也是自定义注解的一种方式,使用了xml配置文件的方式。
<bean class="example.SimpleMovieCatalog">
<qualifier type="Genre" value="Action"/>
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="example.Genre" value="Comedy"/>
</bean>
举例
之前讲到的BeanInterface类有两个实现类BeanImplOne和BeanImplTwo,调用类BeanInvoker。
在调用类里加上代码
@Autowired
@Qualifier("beanImplTwo")
private BeanInterface beanInterface;
if (null != beanInterface) {
System.out.println(beanInterface.getClass().getName());
} else {
System.out.println("beanInterface is null...");
}
由于BeanInterface有两个实现类,所以可以使用@Qualifier注解同时指定具体使用哪一个实现类。然后在say方法里加上之后的代码。
最终的结果表明@Qualifier注解可以缩小范围,指定到具体的bean。