說明:
(1)在【Spring IoC容器與Bean管理21:使用注解方式實作Spring IoC二:元件類型注解(對象執行個體化);@Repository,@Service,@Controller,@Component;】中,僅僅介紹了執行個體化對象,但是沒有涉及為對象的屬性注入資料;本部落格中介紹的【自動裝配注解】,其目的就是實作對象的依賴注入;
(2)【自動裝配注解】包括【按類型裝配注解】和【按名稱裝配注解】;
(3)本篇部落客要介紹以【@Autowired】注解為例,介紹【自動裝配注解】中的【按類型裝配注解】的使用和缺點;
(3)本篇部落格,沿用【Spring IoC容器與Bean管理21:使用注解方式實作Spring IoC二:元件類型注解(對象執行個體化);@Repository,@Service,@Controller,@Component;】中的代碼s08;
目錄
一:自動裝配注解簡介
0.【按類型裝配】注解和【按名稱裝配】注解簡述:
1.【按類型裝配】的注解:@Autowired和@Inject:
2.【按名稱裝配】的注解:@Named和@Resource:
二:自動裝配注解:之【按類型裝配】注解:之@Autowired注解
[email protected]注解用法:【在屬性上使用@Autowired注解】和【在set方法上使用@Autowired注解】
政策一:在userDao屬性上使用@Autowired注解
政策二:在setUserDao()方法上使用@Autowired注解
差別分析:
[email protected]注解用法:缺點和問題
(1)示範:為什麼,在工作中,不推薦使用【按類型裝配注解】;
(2)使用【按類型裝配注解】,如何解決【由于IoC容器中出現多個相同類型的對象,進而導緻的NoUniqueBeanDefinitionException】的問題?
一:自動裝配注解簡介
0.【按類型裝配】注解和【按名稱裝配】注解簡述:
● 【按名稱裝配】:在【Spring IoC容器與Bean管理12:IoC在項目中的作用;】中的s04項目為例:在絕大多數場景下,我們都是采用【按名稱裝配】的政策;
●【按類型裝配】:不需要關心在IoC容器中,bean的名稱是什麼;在運作過程中為屬性注入值時,隻需要從IoC容器中擷取對應類型的對象,然後完成自定注入;
1.【按類型裝配】的注解:@Autowired和@Inject:
● @Autowired:這個是Spring提供的,即這是Spring自己提供的規範;
● @Inject:由JSR-330(Java規範要求第330号檔案,這個檔案是Java領域的标準和業界的規範)提供的标準;自然Spring對JSR-330也提供了支援;
● @Autowired和@Inject這兩個【按類型裝配】的注解,不推薦使用;更多的時候,鼓勵使用【按名稱裝配】的注解;
2.【按名稱裝配】的注解:@Named和@Resource:
● @Named:這個注解要和@Inject注解比對使用;即在@Inject注解後,增加@Named注解,其會按照屬性名(或者其他自定義的規則)完成對象的裝配;同時@Named也是JSR-330(Java規範要求第330号檔案,這個檔案是Java領域的标準和業界的規範)提供的标準
● @Resource:這個注解出現的較早,是JSR-250提供的标準;這個注解不但可以按照名稱進行依賴注入,如果不滿足按名稱進行依賴注入時,其也能自動按類型裝配;@Resource這個注解是目前功能最強大的自動供裝配注解;
二:自動裝配注解:之【按類型裝配】注解:之@Autowired注解
● 沿用【Spring IoC容器與Bean管理21:使用注解方式實作Spring IoC二:元件類型注解(對象執行個體化);@Repository,@Service,@Controller,@Component;】中的代碼s08;
● 在實際工作中,不推薦使用【按類型裝配】注解;
● 事先說明:MVC架構模式采用分層的方式依次的逐級調用的,即Controller調用Service(也就是Controller依賴于Service啦),Service調用Dao(也就是Service依賴于Dao);由于前面,我們在UserController類、UserService類、UserDao類中使用了對應的注解,是以在IoC容器初始化的時候,這三個類的bean對象就會被建立了;
1.@Autowired注解用法:【在屬性上使用@Autowired注解】和【在set方法上使用@Autowired注解】
政策一:在userDao屬性上使用@Autowired注解
運作:通過運作結果,可以看到上面實作了對象注入,但是其并不是通過setter方法來實作的;
但是,如果采用下面的政策:
……………………………………………………
政策二:在setUserDao()方法上使用@Autowired注解
重新運作: ……………………………………………………差別分析:
(1)【在屬性上使用@Autowired注解】和【在set方法上使用@Autowired注解】,都可以完成對象的注入;
(2)【在屬性上使用@Autowired注解】沒有執行set方法;【在set方法上使用@Autowired注解】執行了set方法;
(3)如果裝配注解放在set方法上,則自動按類型或者名稱對set方法參數進行注入;
(4)如果裝配注解放在屬性上,IoC容器會自動通過反射技術,将屬性private修飾符自動更改為public,由于屬性的通路修飾符成了public,這就意味着從外側可以直接對這個屬性指派,不再執行set方法,然後指派完成後,再将修飾符改回到private;(這個過程是在運作時,動态完成的,對程式員不可見) (5)由于(4)中的原因,在實際開發中,如果使用注解來實作對象依賴注入的話,通常是不用寫set方法的;
2.@Autowired注解用法:缺點和問題
(1)示範:為什麼,在工作中,不推薦使用【按類型裝配注解】;
既然有了Dao接口,那麼UserDao類應該實作這個接口(在實際開發中,這也是約定俗成的開發方式): 因為有了所有Dao的接口,那麼在Service中,按照面向對象程式設計的理念,userDao屬性的類型也應該修改為IUserDao接口:至此,還沒有什麼問題。
然後,比如原有的UserDao是基于Mysql資料庫寫的,如果後面需要改為Oracle資料庫,直接的想法是新建立一個類,這個類實作IUserDao接口,然後按照Oracle開發就行了;
但是,這樣以後就會出問題了:運作SpringApplication類,就會報錯了:NoUniqueBeanDefinitionException: 該行報錯資訊完整摘錄如下:Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.imooc.spring.ioc.dao.IUserDao' available: expected single matching bean but found 2: udao,userOracleDao
其大意是,我期望在容器隻有唯一的、比對的bean,但是在容器中發現了兩個bean(分别是userDao和userOracleDao);
之是以會注入失敗,就是因為@Autowired注解是【按類型裝配】的注解;
(2)使用【按類型裝配注解】,如何解決【由于IoC容器中出現多個相同類型的對象,進而導緻的NoUniqueBeanDefinitionException】的問題?
解決辦法1:去掉被抛棄的那個Dao類的@Repository注解;(目的是,IoC容器中不要出現類型重複的Dao對象) 解決辦法2:引入@Primary注解 運作結果:
【按類型裝配】注解之是以容易出問題的原因就是:在容器中,可能會出現多個相同類型的對象,如果稍不注意就會出現NoUniqueBeanDefinitionException;為了避免這個問題,在實際開發中,多使用【按名稱裝配】的注解,因為名稱在容器中都是唯一的,是以可以有效避免剛才錯誤的發生;而【按名稱裝配】的注解在下篇部落格中會給予介紹;