Spring 处理自动装配的歧义性 @Primary 自定义限定符注解@Qualifier

@Autowired

public    void    setDessert(Dessert   dessert){

       this.dessert = dessert;

}

我们使用@Autowired注解标注了setDessert()方法,而他依赖Dessert接口,但是Dessert接口有三个实现类,并且都使用了@Component注解,那么组件扫描的时候,会为这三个实现类实例化bean在Spring上下文中存储,那么setDessert()方法在选择时,由于有三个实现类,不知道使用哪个,Spring则会报错,抛出NoUniqueBeanDefinitionException异常。

解决:我们可以设置某一个为首选bean(使用@Primary)

@Component

@Primary

public   class    IceCream   extends   Dessert(){ .........  }

或则通过显示配置的声明IceCream,那么@Bean方法如下所示:

@Bean

@Primiary

public   Dessert   iceCream(){

   return  new   IceCream();

}

如果你使用的是xml配置的话,那么配置如下:

<bean  id =  "iceCream"   class  =  "com.desserteater.IceCream"   primary="true" />

无论哪种方式,效果一样,都是告诉Spring在遇到歧义性的时候首先该bean.

但是,如果两个bean或则更多的首选bean使用@Primiart,Spring就无法正常工作,因为仍然会有歧义性。

@Qualifier

@Qualifier注解是使用限定符的主要方式,他可以与@Autowired和@Inject协同使用,在注入的时候指定想要注入的bean

@Autowired

@Qualifier("iceCream")

public  void   setDessert(Dessert   dessert){
       this.dessert = dessert;

}

这是最简单的限定符使用例子,为@Qualifier注解所设置的参数就是想要注入的bean的ID,所有使用@Component注解声明的类都会创建为bean,并且bean的ID为首字母变小写的类名。因此,@Qualifier("iceCream")指向的是组件扫描时所创建的bean,并且这个bean是IceCream类的实例。

   更准确的讲,@Qualifier("iceCream")所引用的bean要具有String类型的“iceCream”作为限定符。如果没有指定其他限定符的话,所有的bean都会给定一个默认的限定符,这个限定符与bean的ID相同,即为首字母变小写的类名。因此框架会将有“iceCream”限定符的bean注入到setDessert()方法中。

问题:基于默认的beanID它是为首字母变小写的类名,如果重构了该类,重命名为其他类名的话,比如将IceCream重命名为Gelato,那么上面的setDesser()方法将无法通过限定符匹配,自动装配会失败。

解决:创建自定义限定符⬇️⬇️⬇️

创建自定义的限定符

在bean声明上添加@Qualifier注解,他可以和@Component组合使用

@Component

@Qualifier("cold")

public   class   IceCream   implements   Dessert {   ......  }

在这种情况下,cold限定符分配给了IceCream bean,因为它没有耦合的类名,所以可以任意重构IceCream的类名,而不必担心上面的破坏自动装配问题。在注入的地方引入cold限定符就可以了。

当通过java显示配置bean的时候,@Qualifier也可以和@Bean一起使用

@Bean

@Qualifier("cold")

public  Dessert   iceCream(){

      return  new IceCream();

}

问题:如果相同类型的类都使用一样的@Qualifier注解,那怎么办

Java不允许同一个条目上重复出现相同类型的多个注解。否则会报错,

(注:java 8 允许出现重复的注解,只要这个注解本身定义的时候带有@Repeatable注解就可以。不过Spring的@Qualifier注解并没有在定义时添加@Repeatable注解。)

//java8中允许使用重复注解的demo,注解需要添加@Repeatable
@Repeatable(Authorities.class)
public @interface Authority {
     String role();
}

public @interface Authorities {
    Authority[] value();
}

public class RepeatAnnotationUseNewVersion {
    @Authority(role="Admin")
    @Authority(role="Manager")
    public void doSomeThing(){ }
}

如:

@Component

@Qualifier("cold")

@Qualifier("creamy")

public class   IceCream   implements  Dessert {  ......   }

上面不允许这样操作的,因为@Qualifier没有@Repeatable注解,那么怎么解决呢?  

我们可以创建自定义的限定符注解,借助这样的注解来使bean唯一。我们将不再使用@Qualifier("code"),而是使用自定义的@Code注解,如下所示:

@Target( {ElementType.CONSTRUCTOR,  ElementType.FIELD ElementType.METHOD, ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Qualifier

public  @interface  Cold {   }

当不想使用@Qualifier时,我们通过自定义限定符注解时,添加@Qualifier注解,自定义注解就觉有@Qualifier注解的特性。他们本身实际上也就成为了限定符注解。

那么如果出现上面那个问题,我们可以按层次定义多个注解即可:如

@Component

@Cold

@Creamy

public class   IceCream   implements  Dessert {  ......   }

@Component

@Cold

@Fruity

public class   IceCream   implements  Dessert {  ......   }

猜你喜欢

转载自blog.csdn.net/m0_37668842/article/details/82748821