Sprint Boot————@Qualifier、@Primary
引言
使用@Autowired自動注入時:
如果注入的介面有多個實現類,如下所示:
那麼如果不指定具體是哪個實現類的Bean,在Spring Boot啟動時就會發生異常(下圖請點選檢視):
異常的描述資訊非常簡單,就是告訴開發者,自動注入的地方需要一個Bean,而spring 容器卻找到了3個實現類的Bean。
Action(可以採取的行動): 考慮使用@Primary註解或@Qualifier註解。
@Primary
此註解用在類上面,官方解釋如下:
簡單翻譯過來就是,這個註解相當於Spring 的xml配置檔案中bean標籤裡的 primary屬性。
它表示在需要自動注入一個單值依賴的地方,卻有多個候選依賴,那麼這個註解會指定一個類作為preference(偏好)選擇。
可以簡單理解為,我們把@Primary註解標記在任意一個類上面,在使用@Autowired注入的時候,如果不特殊指明(如何特殊指明請看@Qualifier的講解),那麼預設就注入被@Primary標記的類。
但是隻可以指定一個類作為偏好類,否則依然會產生衝突。
@Qualifier
此註解用在屬性上、方法上、引數上等,官方解釋如下:
翻譯過來就是說,這個註解用在屬性上,或引數上,在自動注入的時候作為多個候選bean的限定。也可以使用在其他的隨後會被用於限定bean的定製註解上。
其實大多數用於屬性上和@Autowired一起聯用。
這個註解有一個引數:
(default關鍵字應該是java8中引入的關鍵字,不過我也是第一次見過這種寫法,可能是孤陋寡聞,各位大神輕噴)
稍微思考一下就可以猜到,如果不為@Qualifier註解指定引數那麼預設使用類的預設別名,即類的首字母小寫,比如:
ChineseTeacher類的預設別名是:chineseTeacher;
EnglishTeacher類的預設別名是:englishTeacher;
MathTeacher類的預設別名是:mathTeacher。
使用預設別名的方法很簡單,直接用類的預設別名來命名我們的自動注入物件,如下所示:
Teacher介面有三個實現類:ChineseTeacher、EnglishTeacher、MathTeacher,我們不需要使用@Primary,也不使用@Qualifier,直接在自動注入的變數上使用預設別名,依然可以注入成功。
是的,當我們在自動注入的時候使用類的預設別名,就不會發生候選Bean衝突的問題。
使用@Qualifier或@Primary註解僅僅是在你不想用預設別名來命名注入的bean或是忘記了使用預設別名的情形。
當我們不使用預設別名來使用自動注入功能,我們就需要使用@Qualifier來指定選擇的型別,像下面這樣:
注意,如果想將ChineseTeacher注入到teacher物件中,就必須給ChineseTeacher類設定別名。
@Service、@Component等註解都可以傳入一個字串作為類的別名。
注意:使用@Qualifier注入bean的時候,它所選取的類的別名需要與具體的類的別名一致,否則會報無法找到指定型別的錯誤。
總結
羅裡吧嗦說了這麼多,其實總結起來很簡單。
我們自動注入的時候,如果有多個候選實現類的bean,spring boot啟動的時候就不知道該選擇哪個bean進行注入,因此會報錯。
使用@Primary可以指定一個首選Bean注入;使用@Qualifier可以在自動注入的地方通過傳入一個限定名(也就是類的別名)來選取指定的實現類,只不過必須與類的別名一致(如果不傳限定名,就使用類的預設別名)
如果既不用@Primary也不用@Qualifier,那就必須在自動注入的時候直接以類的預設別名來命名。
給(spring ioc容器管理的)類設定別名的方式是:@Service("別名")、@Component("別名") 、@Bean("別名") 等等。