在使用IDEA 進行Spring 開發的時候,在字段上面使用@Autowired注解的時候,IDEA 會有警告提示:
翻譯過來就是這個意思:不建議使用基于 field 的注入方式。
Spring 開發團隊建議:在Spring Bean 永遠使用基于constructor 的方式進行依賴注入。對于必須的依賴,永遠使用斷言來確認。
為什么Spring 團隊會提出這樣的建議?直接使用這種基于 field 的注入方式有什么問題?
首先需要知道,Spring 中有這么3種依賴注入的方式 :
- 基于 field 注入(屬性注入)
- 基于 setter 注入
- 基于 constructor 注入(構造器注入)
1. 基于 field 注入
所謂基于 field 注入,就是在bean的變量上使用注解進行依賴注入。本質上是通過反射的方式直接注入到field,所以private的成員也可以被注入具體的對象。這是平常開發中看的最多也是最熟悉的一種方式,同時,也正是 Spring 團隊所不推薦的方式。比如:
@Autowired
private Svc svc;
2. 基于 setter 方法注入
通過對應變量的setXXX()方法以及在方法上面使用注解,來完成依賴注入。比如:
private Helper helper;
@Autowired
public void setHelper(Helper helper) {
this.helper = helper;
}
注:在 Spring 4.3 及以后的版本中,setter 上面的 @Autowired 注解是可以不寫的。
3. 基于 constructor 注入
將各個必需的依賴全部放在帶有注解構造方法的參數中,并在構造方法中完成對應變量的初始化,這種方式,就是基于構造方法的注入,也是日常最為推薦的一種使用方式。這種注入方式很直接,通過對象構建的時候建立關系,所以這種方式對對象創建的順序會有要求,當然Spring會搞定這樣的先后順序,除非出現循環依賴,然后就會拋出異常。比如:
private final Svc svc;
@Autowired
public HelpService(@Qualifier("svcB") Svc svc) {
this.svc = svc;
}
在 Spring 4.3 及以后的版本中,如果這個類只有一個構造方法,那么這個構造方法上面也可以不寫 @Autowired 注解。
Spring 開發團隊的建議
- 強制依賴就用構造器方式
- 可選、可變的依賴就用setter 注入當然可以在同一個類中使用這兩種方法。構造器注入更適合強制性的注入旨在不變性,Setter注入更適合可變性的注入。
Spring 團隊提倡使用基于構造方法的注入,因為這樣一方面可以將依賴注入到一個不可變的變量中 (注:final 修飾的變量) ,另一方面也可以保證這些變量的值不會是 null 。此外,經過構造方法完成依賴注入的組件 (注:比如各個 service),在被調用時可以保證它們都完全準備好了 。與此同時,從代碼質量的角度來看,一個巨大的構造方法通常代表著出現了代碼異味,這個類可能承擔了過多的責任 。
基于 setter 的注入,則只應該被用于注入非必需的依賴,同時在類中應該對這個依賴提供一個合理的默認值。如果使用 setter 注入必需的依賴,那么將會有過多的 null 檢查充斥在代碼中。使用 setter 注入的一個優點是,這個依賴可以很方便的被改變或者重新注入 。