Field injection is not recommended 依賴注入方式

轉載自:https://blog.csdn.net/github_38222176/article/details/79506392

1.背景

這裏寫圖片描述

首先對於還不熟悉@Autowired的同學當然也包括我先去看看它到底有什麼作用。

大體意思就是就是說用了它就可以省去類裏面的set/get方法,也不用在xml文件中要注入的類中設置屬性,它會根據@Autowired註釋自動完成。

言歸正傳,那爲什麼spring team不推薦使用Filed injection呢?

  • 構造器注入
  • Setter(方法)
  • Field injection

2.分類

下面讓我們來比較一下這三種方式。

2.1構造器注入

private DependencyA dependencyA;
private DependencyB dependencyB;
private DependencyC dependencyC;

@Autowired
public DI(DependencyA dependencyA, DependencyB dependencyB, DependencyC dependencyC) {
    this.dependencyA = dependencyA;
    this.dependencyB = dependencyB;
    this.dependencyC = dependencyC;
}

2.2Setter注入

private DependencyA dependencyA;
private DependencyB dependencyB;
private DependencyC dependencyC;

@Autowired
public void setDependencyA(DependencyA dependencyA) {
    this.dependencyA = dependencyA;
}

@Autowired
public void setDependencyB(DependencyB dependencyB) {
    this.dependencyB = dependencyB;
}

@Autowired
public void setDependencyC(DependencyC dependencyC) {
    this.dependencyC = dependencyC;
}

2.3Field 注入

@Autowired
private DependencyA dependencyA;

@Autowired
private DependencyB dependencyB;

@Autowired
private DependencyC dependencyC;

3.分析

問題是什麼

 正如你所見,Field注入看起來非常好,夠簡潔,並且也沒有樣板式的代碼(爲了實現通用和簡單的任務而重複的代碼)。代碼通俗易懂。你的類可以專注於業務而不被依賴注入所污染。你只需要把@Autowired扔到變量之上就好了,不需要特殊的構造器或者set方法,依賴注入容器會提供你所需的依賴。Java本身就非常繁重,所以要儘可能的讓你的代碼簡潔,對嗎?

單一職責侵入原則

添加依賴是很簡單的,可能過於簡單了。添加六個、十個甚至一堆依賴一點也沒有困難。當你使用構造器方式注入,到了某個特定的點,構造器中的參數變得太多以至於很明顯地發現something is wrong。擁有太多的依賴通常意味着你的類要承擔更多的責任。明顯違背了單一職責原則(SRP:Single responsibility principle)。

依賴隱藏

 使用依賴注入容器意味着類不再對依賴負責,獲取依賴的職責從類中抽離出來,依賴容器會幫你裝配。當類不再爲依賴負責,它應該更明確的使用公有的接口方法或構造器,使用這種方式能很清晰的瞭解類需要什麼,也能明確它是可選的(setter注入)還是強制的(構造器注入)。

依賴注入容器耦合

依賴注入框架的核心思想之一就是受容器管理的類不應該去依賴容器所使用的依賴。換句話說,這個類應該是一個簡單的POJO(Plain Ordinary Java Object)能夠被單獨實例化並且你也能爲它提供它所需的依賴。只有這樣,你才能在單元測試中實例化這個類而不必去啓動依賴注入容器,實現測試分離(啓動容器更多是集成測試)。 
 然而,當使用變量直接注入時,沒有一種方式能直接地實例化這個類並且滿足其所有的依賴。這就意味着:

1.有一種方式(調用默認構造器)來創建對象就是使用new關鍵字,但是當這個對象缺少一些必要的依賴,調用的時候就會出現空指針異常。 舉個栗子:
public class DependencyA {
    public void a(){
        System.out.println("dependencyA");
    }
}

public class POJO {
    @Autowired
    private DependencyA dependencyA;

    public void execute(){
        dependencyA.a();
    }
}

public class Test {
    public static void main(String[] args) {
        POJO pojo = new POJO();
        pojo.execute();
    }
}
當你執行execute()方法時就會報空指針異常,是因爲DependencyA沒有被創建,使用這種方式(@Autowired)也不會強制你去創建類所需的依賴,所以當使用者調用的方法的時候就可能會出現空指針異常。 
 2.像這樣的類沒辦法在容器之外被重用,也不能期望反射提供其所需的依賴。

不變性

不向構造器注入,Field注入不能有效地用來指定依賴

構造器注入 VS Setter注入

Setter 
Setter應該被用來注入可變的依賴。當沒有提供依賴時,這個類也應該能夠運轉。當實例化對象後,這些依賴也能隨時改變。其實也視情況而變,有時,一個不變的對象是理想狀態。有時,最好是能在運行期間改變對象的屬性。

構造器 
構造器對注入強制性的的依賴是好的。對象需要這些依賴才能正常運轉,通過構造器提供這些依賴就能保證對象初始化後就能被使用。使用構造器注入的一個可能的影響就是循環依賴。

4.結論

Field注入應該儘可能地去避免使用。作爲替代,你應該使用構構造器注入或Setter注入。他們都有利有弊,需要視情況而定。當然你可以在同一個類中使用這兩種方法。構造器注入更適合強制性的注入旨在不變性,Setter注入更適合可變性的注入。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章