一、前言
我們在使用Spring框架進行開發時,不可避免的要進行依賴注入(Dependency Injection),也就是把實例從Spring容器中取出來進行使用。Spring的依賴注入方式主要有三種,分別為Constructor、Setter和Field。有了選擇的余地,令人糾結的地方就來了,這三種方式哪個更好一些呢?
二、注入方式對比
接下來我們逐一看下這三種注入方式:
Field注入
@Autowired
private DependencyA dependencyA;
優點
- 注入簡單,只需在字段上添加@Autowired或@Resource;
- 減少大量冗余代碼,美觀;
- 新增Field時不需要過多代碼修改;
缺點
- 很難測試,因為沒有帶參構造和set方法,難以在容器以外使用。
- 依賴不能是final的
- 容易出現循環依賴
Setter注入
private DependencyB dependencyB;
@Autowired
public void setDependencyB(DependencyB dependencyB) {
this.dependencyB = dependencyB;
}
優點
-
對循環依賴免疫
-
在對象的整個生命周期內,可以隨時動態的改變依賴。
缺點
- 依賴不能是final的
Constructor注入
private DependencyC dependencyC;
@Autowired
public DI(DependencyC dependencyC) {
this.dependencyC = dependencyC;
}
優點
- 依賴可以是final的
- 高耦合類隨着構造參數的增長很容易被識別出來
- 不需要依賴@Autowired注解(當類中只有一個構造方法時,可以省略@Autowired)
缺點
- 代碼顯得十分臃腫
三、選擇哪種注入方式
Spring官方目前推薦的是構造器注入。根據官方的說法,因為它使人們能夠將應用程序組件實現為不可變對象,並確保所需的依賴項不為null。此外,注入構造函數的組件總是以完全初始化的狀態返回到客戶端(調用)代碼。
- 不可變對象:說的是可以是字段用final關鍵字修飾。
- 依賴不為null:因為有了自定義的構造函數,所以程序不再提供默認的空參構造,類在實例化時必須傳入所有需要的參數。
- 完全初始化的狀態:構造方法的作用就是初始化成員變量,在Java類加載實例化的過程中,構造方法是最后一步,所以返回來的組件都是初始化之后的狀態。
四、總結
三種方式各有利弊,從靠譜程度來說,還是構造器注入更好一些,它能有效避免一些比如循環依賴、空指針等異常的發生。另外,Spring中Bean默認為單例的,有可能會出現線程安全問題,這個時候final就更有必要了。當然,其他兩種方式也有其自己的發光點,我們可以按實際需要選擇使用,或混合使用。