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 {  ......   }

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章