Spring_总结_04_高级配置(三)_处理歧义
一、前言
本文承接上一节:Spring_总结_04_高级配置(二)之条件注解@Conditional
我们前面装配bean时,在Spring容器中,都是只有一个bean能匹配所需的结果。
如果有多个bean能匹配结果的话,Spring就将无法做出选择,这就是自动装配的歧义性。
这一节我们将解决自动装配的歧义性
二、歧义实例
1.实体类
如下,有三个类都继承自Dessert
@Component public class Cake implements Dessert {...} @Component public class Cookies implements Dessert {...} @Component public class IceCream implements Dessert {...}
2.注入bean
@Autowired public void setDessert(Dessert dessert){ this.dessert = dessert; }
3.异常
Spring有选择困难症,当Spring尝试自动装配 setDessert() 中的 Dessert 参数时,发现有三个选择,这时它会抛出一个NoUniqueBeanDefinitionException异常,来表示自己无从选择。
可用 @Primary 和 @Qualifier 来解决歧义问题。
三、@Primary
在声明Bean的时候,通过将其中一个可选的bean设置为首选(primary)Bean,能够避免自动装配的歧义性。
被@Primary注解的bean即可首选Bean。
1.配置首选Bean
配置首选Bean有如下两种方式:
(1)在组件类中配合@Component使用
@Component @Primary public class IceCream implements Dessert {...}
(2)在配置类中配合@Bean使用
@Bean @Primary public Dessert iceCream(){ return new IceCream(); }
2.注入bean
注入bean时,Spring会找到三个可选bean,其中一个是首选bean,因此会选择首选bean进行注入。
@Autowired public void setDessert(Dessert dessert){ this.dessert = dessert; }
注意:Spring 有选择困难症,若配置了两个及以上的首选Bean,则Spring有无从选择了。
四、@Qualifier
Spring 的限定符能够将bean限定到唯一一个满足要求的bean.
1. 基于ID的限定符
为@Qualifier注解所设置的参数就是想要注入的bean的 ID
@Autowired @Qualifier("iceCream") //在注入的时候,指定注入的bean为 iceCream public void setDessert(Dessert dessert){ this.dessert = dessert; }
2. 面向特性的限定符
我们可以为bean设置自己的限定符,而不是依赖于将 bean ID 作为限定符。
可在声明Bean或配置Bean时,使用@Qualifier注解设置限定符。
2.1 设置限定符
(1)在声明Bean时,设置限定符
@Component @Qualifier("cold") //设置限定符为 cold public class IceCream implements Dessert {...}
(2)在配置Bean时,设置限定符
@Bean @Qualifier("cold") //设置限定符为 cold public Dessert iceCream(){ return new IceCream(); }
2.2 使用限定符
@Autowired @Qualifier("cold") //注入限定符为 cold 的bean public void setDessert(Dessert dessert){ this.dessert = dessert; }
3 自定义限定符注解
有时,我们想为bean设置多个限定符,如下:
@Component @Qualifier("cold") //设置限定符为 cold @Qualifier("creamy") //设置限定符为 creamy public class Popsicle implements Dessert {...}
然而,Java不允许在同一个条目上重复出现相同类型的多个注解
为了解决这个问题,我们可以创建自定义的限定符注解。
(1)自定限定符注解
@Cold
@Target({ ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Cold{ }
@Creamy
@Target({ ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Creamy{ }
(2)为bean设置多个限定符
@Component @Cold @Creamy public class IceCream implements Dessert {...}
(3)注入bean时,使用多个限定符来限定
@Autowired @Cold @Creamy public void setDessert(Dessert dessert){ this.dessert = dessert; }