Spring依賴注入中的@Resource與@Autowired詳解
Spring的@Resource與@Autowired
提到Spring依賴注入,大家最先想到應(yīng)該是@Resource和@Autowired,很多文章只是講解了功能上的區(qū)別,對于Spring為什么要支持兩個這么類似的注解卻未提到,屬于知其然而不知其所以然。
不知大家在使用這兩個注解的時候有沒有想過,@Resource又支持名字又支持類型,還要@Autowired干嘛,難道是Spring官方?jīng)]事做了?
真的是沒事做了嗎?讀了本文你將會了解到:
- @Resource和@Autowired來源
- Spring官方為什么會支持這兩個功能如此相似的注解?
- 為什么@Autowired屬性注入的時候Idea會曝出黃色的警告?
- @Resource和@Autowired推薦用法
來源
既然要弄清楚,就要先了解他們的身世。
@Resource 于 2006年5月11日隨著JSR 250 發(fā)布 ,官方解釋是:
Resource 注釋標記了應(yīng)用程序需要的資源。該注解可以應(yīng)用于應(yīng)用程序組件類,或組件類的字段或方法。當注解應(yīng)用于字段或方法時,容器將在組件初始化時將所請求資源的實例注入到應(yīng)用程序組件中。如果注釋應(yīng)用于組件類,則注釋聲明應(yīng)用程序?qū)⒃谶\行時查找的資源。
可以看到它類似一個定義,而由其他的組件或框架自由實現(xiàn)。
@Autowired 于 2007年11月19日隨著Spring2.5發(fā)布,同時官方也對@Resource進行了支持。@Autowired的官方解釋是:
將構(gòu)造函數(shù)、字段、設(shè)置方法或配置方法標記為由 Spring 的依賴注入工具自動裝配。
可以看到,@Autowired 是 Spring的親兒子,而@Resource是Spring對它定義的一種實現(xiàn),它們的功能如此相似。那么為什么要支持了@Resource,又要自己搞個@Autowired呢?
對此專門查了一下Spring2.5的官方文檔,文檔中有一段這么說到:
However, Spring 2.5 dramatically changes the landscape. As described above, the autowiring choices have now been extended with support for the JSR-250 @Resource annotation to enable autowiring of named resources on a per-method or per-field basis. However, the @Resource annotation alone does have some limitations. Spring 2.5 therefore introduces an @Autowired annotation to further increase the level of control.
大概的意思是說,Spring2.5 支持注解自動裝配啦, 現(xiàn)已經(jīng)支持JSR-250 @Resource 基于每個方法或每個字段的命名資源的自動裝配,但是只有@Resource是不行的,我們還推出了“粒度”更大的@Autowired,來覆蓋更多場景了。
嗯哼,那么官方說的“粒度”就是關(guān)鍵了,那“粒度”指的是什么呢”?
既生“@Resource”,何生“@Autowired”
要想找到粒度是什么,我們先從兩個注解的功能下手
@Autowired
- 類型注入
@Resource
- 名字注入優(yōu)先,找不到名字找類型
論功能的“粒度”,@Resource已經(jīng)包含@Autowired了啊,“粒度”更大啊,難道是Spring2.5的時候還不是這樣?我又去翻了下Spring2.5文檔,上面明確的寫到:
When using @Resource without an explicitly provided name, if no Spring-managed object is found for the default name, the injection mechanism will fallback to a type-match.
這不是和現(xiàn)在一樣的嗎,我此時凌亂了。那么“粒度”到底指的是什么?在混跡眾多論壇后,其中stackoverflow的一段話引起了我的注意:
Both @Autowired and @Resource work equally well. But there is a conceptual difference or a difference in the meaning.
@Resource
means get me a known resource by name. The name is extracted from the name of the annotated setter or field, or it is taken from the name-Parameter.
@Inject
or
@Autowired
try to wire in a suitable other component by type.
So, basically these are two quite distinct concepts. Unfortunately the Spring-Implementation of @Resource has a built-in fallback, which kicks in when resolution by-name fails. In this case, it falls back to the @Autowired-kind resolution by-type. While this fallback is convenient, IMHO it causes a lot of confusion, because people are.
大概的意思是:Spring雖然實現(xiàn)了兩個功能類似的,但是存在概念上的差異或含義上的差異:
- @Resource 這按名稱給我一個確定已知的資源。
- @Autowired 嘗試按類型連接合適的其他組件。
但是@Resource當按名稱解析失敗時會啟動。在這種情況下,它會按類型解析,引起概念上的混亂,因為開發(fā)者沒有意識到概念上的差異,而是傾向于使用@Resource基于類型的自動裝配。
原來Spring官方說的“粒度”是指“資源范圍”,@Resource找尋的是確定的已知的資源,相當于給你一個坐標,你直接去找。@Autowired是在一片區(qū)域里面嘗試搜索合適的資源。
所以上面的問題答案已經(jīng)基本明確了。
Spring為什么會支持兩個功能相似的注解呢?
- 它們的概念不同,@Resource更傾向于找已知資源,而Autowired傾向于嘗試按類型搜索資源。
- 方便其他框架遷移,@Resource是一種規(guī)范,只要符合JSR-250規(guī)范的其他框架,Spring就可以兼容。
既然@Resource更傾向于找已知資源,為什么也有按類型注入的功能?
- 個人猜測:可能是為了兼容從Spring切換到其他框架,開發(fā)者就算只使用Resource也是保持Spring強大的依賴注入功能。
Spring的區(qū)別對待
看到這相信大家對使用@Resource還是@Autowired有了自己的見解。
在日常寫代碼中有個小細節(jié)不知道大家有沒有注意到,使用@Autowired在屬性上的時候Idea會曝出黃色的警告,并且推薦我們使用構(gòu)造方法注入,而Resource就不會,這是為什么呢?
警告如下:
為什么@Autowired在屬性上的時候Idea會曝出黃色的警告,并且推薦我們使用構(gòu)造方法注入?
其實Spring文檔中已經(jīng)給出了答案,主要有這幾點:
1、聲明不了常量的屬性
基于屬性的依賴注入不適用于聲明為 final 的字段,因為此字段必須在類實例化時去實例化。聲明不可變依賴項的唯一方法是使用基于構(gòu)造函數(shù)的依賴項注入。
2、容易忽視類的單一原則
一個類應(yīng)該只負責軟件應(yīng)用程序功能的單個部分,并且它的所有服務(wù)都應(yīng)該與該職責緊密結(jié)合。如果使用屬性的依賴注入,在你的類中很容易有很多依賴,一切看起來都很正常。但是如果改用基于構(gòu)造函數(shù)的依賴注入,隨著更多的依賴被添加到你的類中,構(gòu)造函數(shù)會變得越來越大,代碼開始就開始出現(xiàn)“異味”,發(fā)出明確的信號表明有問題。具有超過十個參數(shù)的構(gòu)造函數(shù)清楚地表明該類有太多的依賴,讓你不得不注意該類的單一問題了。因此,屬性注入雖然不直接打破單一原則,但它卻可以幫你忽視單一原則。
3、循環(huán)依賴問題
A類通過構(gòu)造函數(shù)注入需要B類的實例,B類通過構(gòu)造函數(shù)注入需要A類的實例。如果你為類 A 和 B 配置 bean 以相互注入,使用構(gòu)造方法就能很快發(fā)現(xiàn)。
4、依賴注入強依賴Spring容器
如果您想在容器之外使用這的類,例如用于單元測試,不得不使用 Spring 容器來實例化它,因為沒有其他可能的方法(除了反射)來設(shè)置自動裝配的字段。
為什么@Resource沒有呢?
在官方文檔中,我沒有找到答案,查了一些資料說是:@Autowired 是 Spring 提供的,一旦切換到別的 IoC 框架,就無法支持注入了. 而@Resource 是 JSR-250 提供的,它是 Java 標準,我們使用的 IoC 容器應(yīng)該和它兼容,所以即使換了容器,它也能正常工作。
@Autowired和@Resource推薦用法
1. 什么場景用什么合適
記住一句話就行,@Resource傾向于確定性的單一資源,@Autowired為類型去匹配符合此類型所有資源。
如集合注入,@Resource也是可以的,但是建議使用@Autowired。idea左側(cè)的小綠標可以看出來,不建議使用@Resource注入集合資源,本質(zhì)上集合注入不是單一,也是不確定性的。
2. @Autowired推薦用法
方法1 :使用構(gòu)造函數(shù)注入(推薦)
原生版:
優(yōu)雅版:使用lombok的@RequiredArgsConstructor+private final
方法2:set注入
原生版:
優(yōu)雅版:使用lombok的@Setter
簡單總結(jié)一下 @Autowired和@Resource 區(qū)別:
- @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
- Autowired 默認的注入方式為byType(根據(jù)類型進行匹配),可以配合@Qualifier 實現(xiàn) byName 匹配。默認注入的值必須存在,否則報錯。除非required = false
- @Resource默認注入方式為 byName(根據(jù)名稱進行匹配),如果byName沒有則按照byType匹配,默認注入的值不存在,不會報錯。
- 當一個接口存在多個實現(xiàn)類的情況下,@Autowired 和@Resource都需要通過名稱才能正確匹配到對應(yīng)的 Bean。Autowired 可以通過 @Qualifier 注解來顯式指定名稱,@Resource可以通過 name 屬性來顯式指定名稱。
到此這篇關(guān)于Spring依賴注入中的@Resource與@Autowired詳解的文章就介紹到這了,更多相關(guān)Spring的@Resource與@Autowired內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合BCrypt實現(xiàn)密碼加密
這篇文章主要為大家詳細介紹了SpringBoot整合BCrypt進行密碼加密,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11Java 在Excel中添加分離型餅圖、環(huán)形圖的方法
這篇文章主要介紹了Java 在Excel中添加分離型餅圖、環(huán)形圖的方法,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-12-12在Spring項目中引入高版本依賴并解決低版本沖突問題的解決方法
在Spring項目的開發(fā)過程中,依賴管理是一個非常重要且復(fù)雜的問題,我們可能需要引入更高版本的依賴來使用新特性或修復(fù)舊版本的Bug,然而,這些高版本依賴可能會與項目中已有的低版本依賴產(chǎn)生沖突,本文將詳細探討如何在Spring中引入高版本依賴,并解決低版本依賴沖突的問題2025-03-03