為什么Spring和IDEA都不推薦使用 @Autowired 注解
前言
請看下面幾個問題
- Spring為什么不推薦使用
@Autowired
注解? - 為什么推薦使用
@Resource
代替@Autowired
注解? - 如何快速使用構造注入代替
@Autowired
? @Autowired, @Qualifier, @Resource,
三者有何區(qū)別?
下面, 我們帶著以上問題去梳理和學習, 體會知識之間的關聯(lián)性
Spring為什么不推薦使用@Autowired 注解
背景
做開發(fā)的同學可能都會發(fā)現(xiàn), idea 在我們經(jīng)常使用的@Autowired
注解上添加了警告
警告內(nèi)容是: Field injection is not recommended
, 譯為: 不推薦使用屬性注入
我們點擊右側三個小點查看描述, 可以看到信息如下圖
原因詳情描述: Inspection info: Spring Team recommends: "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies".
譯為: Spring 團隊建議: 始終在您的 bean 中使用基于構造函數(shù)的依賴注入。始終對強制依賴項使用斷言
原因
為什么 Spring 建議我們在Bean中使用構造注入呢?
想要回答這個問題, 我們需要了解 Spring的依賴注入(DI)方式
Spring常用的注入方式有: 簡單類型注入, 集合類型注入, 域?qū)傩宰詣幼⑷? 自動注入的類別, 空值注入, 構造注入
可以簡化為: 屬性注入, 構造方法注入, set 方法注入
下面, 來用代碼展示下三種方式注入
屬性注入
可以看到, 我們開發(fā)最常用的就是屬性注入
@RestController public class AppointmentNumberConfigurationController { @Autowired private AppointmentNumberConfigurationService numberConfigurationService; }
set 方法注入
set 方法注入也會用到@Autowired
注解,但使用方式與屬性注入有所不同,
屬性注入是用在成員變量上,而set 方法的時候,是用在成員變量的Setter函數(shù)上。
@RestController public class AppointmentNumberConfigurationController { private AppointmentNumberConfigurationService numberConfigurationService; @Autowired public void setNumberConfigurationService(AppointmentNumberConfigurationService numberConfigurationService) { this.numberConfigurationService = numberConfigurationService; }
構造方法注入
Constructor Injection是構造器注入,是我們最為推薦的一種使用方式。
但是, 每次注入都按照這樣的流程去構造注入的話, 會顯得比較麻煩.
至于如何去簡化這一步驟, 我們可以繼續(xù)往下看.
@RestController public class AppointmentNumberConfigurationController { final AppointmentNumberConfigurationService numberConfigurationService; public AppointmentNumberConfigurationController(AppointmentNumberConfigurationService numberConfigurationService) { this.numberConfigurationService = numberConfigurationService; } }
三種方式對比如下
使用屬性注入可能會出現(xiàn)的問題
基于屬性注入的方式, 違背單一職責原則
因為現(xiàn)在的業(yè)務一般都會使用很多依賴, 但擁有太多的依賴通常意味著承擔更多的責任,而這顯然違背了單一職責原則.
并且類和依賴容器強耦合,不能在容器外使用。
基于屬性注入的方式, 容易導致Spring 初始化失敗
因為現(xiàn)在在Spring特別是Spring Boot使用中, 經(jīng)常會因為初始化的時候, 由于屬性在被注入前就引用而導致npe(空指針錯誤),
進而導致容器初始化失敗(類似下面代碼塊). Java 在初始化一個類時,
是按照 靜態(tài)變量或靜態(tài)語句塊 –> 實例變量或初始化語句塊 –> 構造方法 -> @Autowired 的順序。
所以在執(zhí)行這個類的構造方法時,person 對象尚未被注入,它的值還是 null。
通過@Autowired 注入, 又因為是 ByType 注入, 因此有可能會出現(xiàn)兩個相同的類型bean
如下代碼快, 就會產(chǎn)生兩個相同的Bean, 進而導致Spring 裝配失敗
//2. 基于屬性注入的方式, 容易導致Spring 初始化失敗 @Autowired private Person person; private String company; public UserServiceImpl(){ this.company = person.getCompany(); } //3. 通過@Autowired 注入, 又因為是 ByType 注入, 因此有可能會出現(xiàn)兩個相同的類型bean public interface IUser { void say(); } @Service public class User1 implements IUser{ @Override public void say() { } } @Service public class User2 implements IUser{ @Override public void say() { } } @Service public class UserService { @Autowired private IUser user; }
解決
如果一定要使用屬性注入, 可以使用 @Resource
代替 @Autowired
注解@Resource
的作用相當于@Autowired
,只不過@Autowired
按照byType
自動注入。
如果我們想使用按照名稱byName
來裝配,可以結合@Qualifier
注解一起使用。
如果可能的話, 盡量使用構造注入
Lombok提供了一個注解@RequiredArgsConstructor
, 可以方便我們快速進行構造注入, 例如:
@RestController @RequiredArgsConstructor public class AppointmentNumberConfigurationController { final AppointmentNumberConfigurationService numberConfigurationService; }
同時需要注意:
使用@RequiredArgsConstructor
注解需要導入Lombok 包 或者安裝lombok 插件
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency>
必須聲明的變量為final
根據(jù)構造器注入的,相當于當容器調(diào)用帶有一組參數(shù)的類構造函數(shù)時,基于構造函數(shù)的 DI 就完成了,
其中每個參數(shù)代表一個對其他類的依賴?;跇嬙旆椒閷傩再x值,容器通過調(diào)用類的構造方法將其進行依賴注入
思考
為什么推薦使用@Resource,不推薦使用@Autowired
通過對問題1 的梳理, 我們可以知道.
因為@Autowired
注解在Bean 注入的時候是基于ByType
, 因此會由于注入兩個相同類型的Bean導致裝配失敗
@Resource
的作用相當于@Autowired
,只不過@Autowired
按照byType
自動注入。
如果我們想使用按照名稱byName
來裝配,可以結合@Qualifier
注解一起使用。
@Resource
裝配順序:
①如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則拋出異常。
②如果指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常。
③如果指定了type,則從上下文中找到類似匹配的唯一bean進行裝配,找不到或是找到多個,都會拋出異常。
④如果既沒有指定name,又沒有指定type,則自動按照byName
方式進行裝配;如果沒有匹配,則回退為一個原始類型進行匹配,如果匹配則自動裝配。
因此, 如果一定要使用屬性注入, 可以使用 @Resource 代替 @Autowired 注解
@Autowired, @Qualifier, @Resource, 三者有何區(qū)別
@Autowired
: 通過byType
方式進行裝配, 找不到或是找到多個,都會拋出異常。@Qualifier
: 如果想讓@Autowired
注入的Bean進行byName
裝配, 可以使用@Qualifier
進行指定@Resource
:作用相當于@Autowired
,只不過@Resource
默認按照byName
方式裝配, 如果沒有匹配, 則退回到byType
方式進行裝配
參考文檔
@Autowired和@Resource的區(qū)別是什么?
到此這篇關于為什么Spring和IDEA都不推薦使用 @Autowired 注解的文章就介紹到這了,更多相關Spring IDEA @Autowired 注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java Map 在put值時value值不被覆蓋的解決辦法
這篇文章主要介紹了Java Map 在put值時value值不被覆蓋的解決辦法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-04-04spring如何實現(xiàn)依賴注入DI(spring-test方式)
本文主要介紹如何實現(xiàn)spring 的依賴注入,并且淺顯的講述一下注入需要注意的事項。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03SpringBoot單元測試使用@Test沒有run方法的解決方案
這篇文章主要介紹了SpringBoot單元測試使用@Test沒有run方法的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01java中List數(shù)組用逗號分隔開轉成字符串2種方法
在我們?nèi)粘i_發(fā)中,在前后端交互的時候會遇到多個id或其他字段存放到一個字段中,這時我們會遇到一個List(集合)---->String(單個字段),這篇文章主要給大家介紹了關于java中List數(shù)組用逗號分隔開轉成字符串的2種方法,需要的朋友可以參考下2023-10-10Java實現(xiàn)在Word中嵌入多媒體(視頻、音頻)文件
這篇文章主要介紹了Java如何實現(xiàn)在Word中嵌入多媒體(視頻、音頻)文件,文中的示例代碼講解詳細,對我們學習java有一定的幫助,感興趣的同學可以了解一下2021-12-12Spring Cloud動態(tài)配置刷新RefreshScope使用示例詳解
這篇文章主要為大家介紹了Spring Cloud動態(tài)配置刷新RefreshScope使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08