Spring实战之bean重复、指定bean的名字、消除bean的歧义性
admin
2024-03-18 06:50:16

Spring实战之bean重复、指定bean的名字、消除bean的歧义性

  • 自动装配的歧义性示例
  • 解决方案
    • @Primary标示首选bean
      • @Primary注解与@Component注解配合使用
      • @Primary与JavaConfig配合使用
    • @Qualifier限定符
    • 创建自定义限定符
      • 与组件扫描搭配使用
      • 与JavaConfig搭配使用
    • 自定义注解实现限定符效果
      • 与组件扫描搭配使用
      • 与JavaConfig搭配使用

在 Spring实战之Bean的主要装配机制之一-通过Java代码显示装配bean和 Spring实战之Bean的主要装配机制之一-组件扫描、自动装配bean中,我们了解到bena的转配,但是这是在容器中只有一个同类bean的情况下完成的。如果有同类型实现类的bean呢?这种歧义性会阻碍Spring自动装配属性、构造器参数或方法参数。

自动装配的歧义性示例

解释自动装配的歧义性,如下:

public interface Dessert {
}@Component
public class Cake implements Dessert{
}@Component
public class Cookies implements Dessert{
}@Component
public class IceCream implements Dessert{
}@Configuration
@ComponentScan
public class TestConfig {private Dessert dessert;@Autowiredpublic void setDessert(Dessert dessert){this.dessert = dessert;}
}

本例中,Dessert是要一个接口,并且有三个实现类:Cake、Cookies、IceCream。因这三个实现类都使用了@Component注解,在主键扫描的时候,能够发现它们并将它们创建为Sping上下文里的bean,然后Spring在自动装配setDessert()中的Dessert参数时,由于没有唯一、无歧义的可选值,Spring会抛出异常:

Parameter 0 of method setDessert in com.example.springboot.config.TestConfig required a single bean, but 3 were found:- cake: defined in file [Cake.class]- cookies: defined in file [Cookies.class]- iceCream: defined in file [IceCream.class]

怎么解决如上歧义性问题呢?Spring提供的了众多解决方案,接下来我们使用设置首选bean(primary)或者使用限定符(qualifier)。

解决方案

@Primary标示首选bean

当你都喜欢上述Cake、Cookies、IceCream这三个甜点时,选择一个你最喜欢的那个,加上@Primary注解来标示你最喜欢它。在声明bean的时候,通过@Primary注解来设置为首选,告诉Spring,当自动装配遇到歧义性的时候,Spring将会使用首选的bean。

@Primary注解与@Component注解配合使用

代码如下:

@Component
@Primary
public class IceCream implements Dessert {
}

@Primary与JavaConfig配合使用

代码如下:

    @Bean@Primarypublic Dessert iceCream(){return new IceCream();}

综上,在多个bean中选取一个bean成为首选bean。可是如果有多个bean都被加上了@Primary注解,在有多个首选bean的设置时,Spring也会无法选择装配哪个bean了!此时,可以为了解决这种歧义性,可以使用限定符(qualifier)。

@Qualifier限定符

@Qualifier注解是使用限定符的主要方式,它可以与@Autowired和@Inject协同使用,在注入的时候指定想要注入进去的那个bean。
例如,我们要确保将IceCream注入到setDessert()之中,代码如下:

    @Autowired@Qualifier("iceCream")public void setDessert(Dessert dessert){this.dessert = dessert;}

@Qualifier(“iceCream”)指向的bean是组件扫描时所创建的bean,即IceCream的实例。
但是需要注意的是,限定符中指定的bean是与注入的bean的名称紧耦合的,对类名称的修改,都会导致限定符失效!

创建自定义限定符

与组件扫描搭配使用

代码如下:

@Component
@Qualifier("cold")
public class IceCream implements Dessert {
}

限定符cold分配给了IceCream bean,没有耦合类名,此时可以随意重构IceCream的类名,而不必担心破会自动装配。在注入时,使用cold限定符就可以了:

    @Autowired@Qualifier("cold")public void setDessert(Dessert dessert){this.dessert = dessert;}

与JavaConfig搭配使用

    @Bean@Qualifier("cold")public Dessert iceCream(){return new IceCream();}

自定义注解实现限定符效果

自定义一个注解来标示特定bean。

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD,ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold {
}

与组件扫描搭配使用

实现类上加上自定义注解:

@Component
@Cold
public class IceCream implements Dessert {
}

注入时,加上自定义注解

    @Autowired@Coldpublic void setDessert(Dessert dessert){this.dessert = dessert;}

与JavaConfig搭配使用

	@Bean@Cold//bean声明cold限定符public Dessert iceCream(){return new IceCream();}@Autowired@Cold//注入cold限定符指定的beanpublic void setDessert(Dessert dessert){this.dessert = dessert;}

相关内容

热门资讯

山水皆有情!丽江两山一江的千年... 去过丽江、走过虎跳峡的人,大概率都听过哈巴雪山和金沙江的传说。很多人站在峡谷之下,望着奔腾不息的金沙...
活力中国调研行丨“殷”你而来 ... 9月12日,游客在殷墟博物馆“甲骨文展厅”内参观。位于河南省安阳市的殷墟博物馆新馆是首个全景式展现商...
浦江之夜赴美好相逢,第37届上... 9月12日晚,黄浦江畔灯火璀璨,第37届上海旅游节大巡游在外滩中山东一路上演。不少观众早早便来到外滩...
美丽中国丨秋韵紫鹊界 梯田入画... 这是9月11日拍摄的紫鹊界梯田(无人机照片)。 金秋九月,湖南省娄底市新化县紫鹊界梯田稻谷渐次成熟。...
中国之巅奏响《共同的节日》,千... 千吨阻尼器,“迎世赛、游上海旅游节”。9月13日,由上海市文化和旅游局指导推出上海旅游·会客│巅峰之...