spring中@autowired、@Qualifier、@Primary注解的使用說(shuō)明
@autowired、@Qualifier、@Primary注解的使用
學(xué)過(guò)spring的朋友應(yīng)該都知道@Autowired注解,將IOC容器中的屬性注入到當(dāng)前屬性中。
一:當(dāng)前屬性不是必須的時(shí)
@Autowired注解有且只有這一個(gè)屬性
@Autowired(required = false)
二:容器中存在多個(gè)同種類(lèi)型的組建
1:通過(guò)指定屬性的名字與容器中組建id相同選擇注入的組建
2:通過(guò)@Qualifier注解選擇注入組建的id
@Qualifier("bookDao2") @Autowired(required = false) private BookDao bookDao;
3:通過(guò)@Primary注解在注入組建時(shí)指定使用組建主要選擇哪一個(gè),注入時(shí)將優(yōu)先選擇帶有@Primary注解的組建。
當(dāng)同時(shí)使用@Qualifier注解和@Primary注解時(shí),當(dāng)然優(yōu)先使用@Qualifier注解指定的組建
@Primary @Bean(name = "bookDao2") public BookDao bookDao(){ BookDao bookDao = new BookDao(); bookDao.setLable(2); return bookDao; }
@Autowired @Resource @Qualifier @Primary的區(qū)別
@Autowired @Resource @Qualifier的區(qū)別
實(shí)用理解:@Autowired @Resource 二選其一,看中哪個(gè)就用哪個(gè)。
簡(jiǎn)單理解:
@Autowired
根據(jù)類(lèi)型注入,@Resource
默認(rèn)根據(jù)名字注入,其次按照類(lèi)型搜索@Autowired
@Qualifie(“userService”)
兩個(gè)結(jié)合起來(lái)可以根據(jù)名字和類(lèi)型注入
復(fù)雜理解:
比如你有這么一個(gè)Bean
@Service(“UserService”) public Class UserServiceImpl implements UserService{}; 現(xiàn)在你想在UserController 里面使用這個(gè)UserServiceImpl public Class UserController {
@AutoWire
//當(dāng)使用這個(gè)注入的時(shí)候上面的 UserServiceImpl 只需要這樣寫(xiě) @Service,這樣就會(huì)自動(dòng)找到UserService這個(gè)類(lèi)型以及他的子類(lèi)型。UserServiceImpl 實(shí)現(xiàn)了UserService,所以能夠找到它。不過(guò)這樣有一個(gè)缺點(diǎn),就是當(dāng)UserService實(shí)現(xiàn)類(lèi)有兩個(gè)以上的時(shí)候,這個(gè)時(shí)候會(huì)找哪一個(gè)呢,這就造成了沖突,所以要用@AutoWire注入的時(shí)候要確保UserService只有一個(gè)實(shí)現(xiàn)類(lèi)。@Resource
默認(rèn)情況下是按照名稱(chēng)進(jìn)行匹配,如果沒(méi)有找到相同名稱(chēng)的Bean,則會(huì)按照類(lèi)型進(jìn)行匹配,有人可能會(huì)想了,這下好了,用這個(gè)是萬(wàn)能的了,不用管名字了,也不用管類(lèi)型了,但這里還是有缺點(diǎn)。首先,根據(jù)這個(gè)注解的匹配效果可以看出,它進(jìn)行了兩次匹配,也就是說(shuō),如果你在UserService這個(gè)類(lèi)上面這樣寫(xiě)注解,@Service,它會(huì)怎么找呢,首先是找相同名字的,如果沒(méi)有找到,再找相同類(lèi)型的,而這里的@Service沒(méi)有寫(xiě)名字,這個(gè)時(shí)候就進(jìn)行了兩次搜索,顯然,速度就下降了許多。也許你還會(huì)問(wèn),這里的@Service本來(lái)就沒(méi)有名字,肯定是直接進(jìn)行類(lèi)型搜索啊。其實(shí)不是這樣的,UserServiceImpl 上面如果有@Service默認(rèn)的名字 是這個(gè)userServiceImpl,注意看,就是把類(lèi)名前面的大寫(xiě)變成小寫(xiě),就是默認(rèn)的Bean的名字了。 @Resource根據(jù)名字搜索是這樣寫(xiě)@Resource(“userService”),如果你寫(xiě)了這個(gè)名字叫userService,那么UserServiceImpl上面必須也是這個(gè)名字,不然還是會(huì)報(bào)錯(cuò)。@Autowired
@Qualifie(“userService”)
是直接按照名字進(jìn)行搜索,也就是說(shuō),對(duì)于UserServiceImpl 上面@Service注解必須寫(xiě)名字,不寫(xiě)就會(huì)報(bào)錯(cuò),而且名字必須是@Autowired @Qualifie(“userService”) 保持一致。如果@Service上面寫(xiě)了名字,而@Autowired @Qualifie() ,一樣會(huì)報(bào)錯(cuò)。
private UserService userService; }
說(shuō)了這么多,可能你有些說(shuō)暈了,那么怎么用這三個(gè)呢,要實(shí)際的工作是根據(jù)實(shí)際情況來(lái)使用的,通常使用AutoWire和@Resource多一些,bean的名字不用寫(xiě),而UserServiceImpl上面能會(huì)這樣寫(xiě) @Service(“userService”)。這里的實(shí)際工作情況,到底是什么情況呢?說(shuō)白了就是整個(gè)項(xiàng)目設(shè)計(jì)時(shí)候考慮的情況,如果你的架構(gòu)設(shè)計(jì)師考慮的比較精細(xì),要求比較嚴(yán)格,要求項(xiàng)目上線后的訪問(wèn)速度比較好,通常是考慮速度了。這個(gè)時(shí)候@AutoWire沒(méi)有@Resource好用,因?yàn)锧Resource可以根據(jù)名字來(lái)搜索,是這樣寫(xiě)的@Resource(“userService”)。這個(gè)@Autowired @Qualifie(“userService”) 也可以用名字啊,為什么不用呢,原因很簡(jiǎn)單,這個(gè)有點(diǎn)長(zhǎng),不喜歡,增加工作量。因?yàn)楦鶕?jù)名字搜索是最快的,就好像查數(shù)據(jù)庫(kù)一樣,根據(jù)Id查找最快。因?yàn)檫@里的名字與數(shù)據(jù)庫(kù)里面的ID是一樣的作用。這個(gè)時(shí)候,就要求你多寫(xiě)幾個(gè)名字,工作量自然就增加了。而如果你不用注解,用xml文件的時(shí)候,對(duì)于注入Bean的時(shí)候要求寫(xiě)一個(gè)Id,xml文件時(shí)候的id就相當(dāng)于這里的名字。
說(shuō)了那么多沒(méi)用,你能做的就是簡(jiǎn)單直接,什么最方便就用什么,
你就直接用@Resource得了,如果你喜歡用@AutoWire也行,不用寫(xiě)名字。
通常情況一個(gè)Bean的注解寫(xiě)錯(cuò)了,會(huì)報(bào)下面這些錯(cuò)誤,最為常見(jiàn),
No bean named ‘user' is defined,這個(gè)表示沒(méi)有找到被命名為user的Bean,通俗的說(shuō),就是名字為user的類(lèi)型,以及它的子類(lèi)型,出現(xiàn)這個(gè)錯(cuò)誤的原因就是注入時(shí)候的類(lèi)型名字為user,而搜索的時(shí)候找不到,也就是說(shuō)可能那個(gè)搜索的類(lèi)型,并沒(méi)有命令為user,解決辦法就是找到這個(gè)類(lèi)型,去命令為user,
下面這個(gè)錯(cuò)誤也常見(jiàn),
No qualifying bean of type [com.service.UserService] found for dependency:
這個(gè)錯(cuò)誤的原因就是類(lèi)型上面沒(méi)有加@Service這個(gè)注入,不僅僅是@Service,如果是其他層也會(huì)出現(xiàn)這個(gè)錯(cuò)誤,這里我是以Service為例子說(shuō)明,如果是DAO層就是沒(méi)有加@Repository,Controller層,則是沒(méi)有加@Controller。
還有,如果你還是想再簡(jiǎn)單點(diǎn),無(wú)論是DAO,Controller,Service三個(gè)層,都可以用這個(gè)注解,@Component,這個(gè)注解通用所有的Bean,這個(gè)時(shí)候你可能會(huì)說(shuō)了,有通常的為什么用的人少呢,那是因?yàn)镸VC這個(gè)分層的設(shè)計(jì)原則,用@Repository,@Service,@Controller,這個(gè)可以區(qū)別MVC原則中的DAO,Service,Controller。便于識(shí)別。
@Qualifier VS @Primary
還有另一個(gè)名為 @Primary 的注解,我們也可以用來(lái)發(fā)生依賴(lài)注入的歧義時(shí)決定要注入哪個(gè) bean。當(dāng)存在多個(gè)相同類(lèi)型的 bean 時(shí),此注解定義了首選項(xiàng)。除非另有說(shuō)明,否則將使用與 @Primary 注釋關(guān)聯(lián)的 bean 。
我們來(lái)看一個(gè)例子:
@Bean public Employee tomEmployee() { return new Employee("Tom"); } @Bean @Primary public Employee johnEmployee() { return new Employee("john"); }
在此示例中,兩個(gè)方法都返回相同的 Employee類(lèi)型。Spring 將注入的 bean 是方法 johnEmployee 返回的 bean。這是因?yàn)樗?@Primary 注解。當(dāng)我們想要指定默認(rèn)情況下應(yīng)該注入特定類(lèi)型的 bean 時(shí),此注解很有用。
如果我們?cè)谀硞€(gè)注入點(diǎn)需要另一個(gè) bean,我們需要專(zhuān)門(mén)指出它。我們可以通過(guò) @Qualifier 注解來(lái)做到這一點(diǎn)。例如,我們可以通過(guò)使用 @Qualifier 注釋來(lái)指定我們想要使用 tomEmployee 方法返回的 bean 。
值得注意的是,如果 @Qualifier 和 @Primary 注釋都存在,那么 @Qualifier 注釋將具有優(yōu)先權(quán)。基本上,@Primary 是定義了默認(rèn)值,而 @Qualifier 則非常具體。
當(dāng)然@Component 也可以使用@Primary 注解,這次使用的還是上面的示例:
@Component @Primary public class FooFormatter implements Formatter { public String format() { return "foo"; } } @Component public class BarFormatter implements Formatter { public String format() { return "bar"; } }
在這種情況下,@Primary 注解指定了默認(rèn)注入的是 FooFormatter,消除了場(chǎng)景中的注入歧義。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java常見(jiàn)延遲隊(duì)列的實(shí)現(xiàn)方案總結(jié)
Java延遲隊(duì)列(DelayQueue)是Java并發(fā)包中的一個(gè)類(lèi),它實(shí)現(xiàn)了BlockingQueue接口,且其中的元素必須實(shí)現(xiàn)Delayed接口,延遲隊(duì)列中的元素按照延遲時(shí)間的長(zhǎng)短進(jìn)行排序,本文給大家介紹了Java常見(jiàn)延遲隊(duì)列的實(shí)現(xiàn)方案總結(jié),需要的朋友可以參考下2024-03-03idea企業(yè)開(kāi)發(fā)之新建各類(lèi)型項(xiàng)目的詳細(xì)教程
這篇文章主要介紹了idea企業(yè)開(kāi)發(fā)之新建各類(lèi)型項(xiàng)目的詳細(xì)教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12Java利用OSHI實(shí)現(xiàn)獲取機(jī)器的硬件信息
OSHI(Operating System and Hardware Information)是一個(gè)開(kāi)源的Java庫(kù),用于獲取操作系統(tǒng)和硬件的詳細(xì)信息,下面我們就來(lái)看看他的具體使用吧2024-11-11Mybatis多表關(guān)聯(lián)查詢(xún)的實(shí)現(xiàn)(DEMO)
本節(jié)要實(shí)現(xiàn)的是多表關(guān)聯(lián)查詢(xún)的簡(jiǎn)單demo。場(chǎng)景是根據(jù)id查詢(xún)某商品分類(lèi)信息,并展示該分類(lèi)下的商品列表,需要的朋友可以參考下2017-02-02Redisson延遲隊(duì)列執(zhí)行流程源碼解析
這篇文章主要為大家介紹了Redisson延遲隊(duì)列執(zhí)行流程源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09Java調(diào)用DeepSeek?API的最佳實(shí)踐及詳細(xì)代碼示例
這篇文章主要介紹了如何使用Java調(diào)用DeepSeek?API,包括獲取API密鑰、添加HTTP客戶(hù)端依賴(lài)、創(chuàng)建HTTP請(qǐng)求、處理響應(yīng)、錯(cuò)誤處理、測(cè)試和部署,文章還提供了代碼示例和注意事項(xiàng),幫助開(kāi)發(fā)者順利完成API調(diào)用,需要的朋友可以參考下2025-02-02SpringBoot項(xiàng)目中同時(shí)操作多個(gè)數(shù)據(jù)庫(kù)的實(shí)現(xiàn)方法
在實(shí)際項(xiàng)目開(kāi)發(fā)中可能存在需要同時(shí)操作兩個(gè)數(shù)據(jù)庫(kù)的場(chǎng)景,本文主要介紹了SpringBoot項(xiàng)目中同時(shí)操作多個(gè)數(shù)據(jù)庫(kù)的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03Java 實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(chóng)框架詳細(xì)代碼
這篇文章主要介紹了Java 實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(chóng)框架,主要是用于爬取網(wǎng)絡(luò)上一些內(nèi)容,比如超鏈接之類(lèi)的,需要的朋友可以參考下面文章內(nèi)容2021-09-09