當前位置: 妍妍網 > 碼農

公司禁止在 SpringBoot 中使用 @Autowired 註解,為什麽?

2024-06-11碼農

Spring 官方已不推薦使用 Autowired 欄位/內容註入 bean,一些大公司的新計畫也明令禁止使用了。

說明

最近公司升級框架,由原來的 spring framework 3.0 升級到 5.0,然後寫程式碼的時候突然發現 idea 在內容註入的 @Autowired 註解上給出警告提示,就像下面這樣的,也是挺懵逼的,畢竟這麽寫也很多年了。

Field injection is not recommended

查閱了相關文件了解了一下,原來這個提示是 spring framework 4.0 以後開始出現的,spring 4.0 開始就不推薦使用內容註入,改為推薦構造器註入和 setter 註入。

下面將展示了 spring 框架可以使用的不同型別的依賴註入,以及每種依賴註入的適用情況。

依賴註入的型別

盡管針對 spring framework 5.1.3 的文件只定義了兩種主要的依賴註入型別,但實際上有三種:

  • 基於構造器的依賴註入

  • 基於 setter 的依賴註入

  • 基於欄位的依賴註入

  • 其中基於欄位的依賴註入被廣泛使用,但是 idea 或者其他靜態代分碼析工具會給出提示資訊,不推薦使用。

    甚至可以在一些 Spring 官方指南中看到這種註入方法:

    2.1 基於構造器的依賴註入

    在基於建構函式的依賴註入中,類建構函式被標註為 @Autowired,並包含了許多與要註入的物件相關的參數。

    @Component
    public classConstructorBasedInjection{
    privatefinal InjectedBean injectedBean;
    @Autowired
    publicConstructorBasedInjection(InjectedBean injectedBean){
    this.injectedBean = injectedBean;
    }
    }

    然後在spring官方文件中,@Autowired 註解也是可以省去的。

    public classSimpleMovieLister{
    // the SimpleMovieLister has a dependency on a MovieFinder
    private MovieFinder movieFinder;
    // a constructor so that the Spring container can inject a MovieFinder
    publicSimpleMovieLister(MovieFinder movieFinder){
    this.movieFinder = movieFinder;
    }
    // business logic that actually uses the injected MovieFinder is omitted...
    }

    基於建構函式註入的主要優點是可以將需要註入的欄位聲明為 final, 使得它們會在類例項化期間被初始化,這對於所需的依賴項很方便。

    2.2 基於 Setter 的依賴註入

    在基於 setter 的依賴註入中,setter 方法被標註為 @Autowired。一旦使用無參數建構函式或無參數靜態工廠方法例項化 Bean,為了註入 Bean 的依賴項,Spring 容器將呼叫這些 setter 方法。

    @Component
    public classSetterBasedInjection{
    private InjectedBean injectedBean;
    @Autowired
    publicvoidsetInjectedBean(InjectedBean injectedBean){
    this.injectedBean = injectedBean;
    }
    }

    和基於構造器的依賴註入一樣,在官方文件中,基於 Setter 的依賴註入中的 @Autowired 也可以省去。

    public classSimpleMovieLister{
    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;
    // a setter method so that the Spring container can inject a MovieFinder
    publicvoidsetMovieFinder(MovieFinder movieFinder){
    this.movieFinder = movieFinder;
    }
    // business logic that actually uses the injected MovieFinder is omitted...
    }

    2.3 基於內容的依賴註入

    在基於內容的依賴註入中,欄位/內容被標註為 @Autowired。一旦類被例項化,Spring 容器將設定這些欄位。

    @Component
    public classFieldBasedInjection{
    @Autowired
    private InjectedBean injectedBean;
    }

    正如所看到的,這是依賴註入最幹凈的方法,因為它避免了添加樣板程式碼,並且不需要聲明類的建構函式。程式碼看起來很幹凈簡潔,但是正如程式碼檢查器已經向我們暗示的那樣,這種方法有一些缺點。

    基於欄位的依賴註入缺陷

    3.1 不允許聲明不可變域

    基於欄位的依賴註入在聲明為 final/immutable 的欄位上不起作用,因為這些欄位必須在類例項化時例項化。聲明不可變依賴項的唯一方法是使用基於構造器的依賴註入。

    3.2 容易違反單一職責設計原則

    在物件導向的編程中,五大設計原則SOLID被廣泛套用,(國內一般為六大設計原則),用以提高程式碼的重用性,可讀性,可靠性和可維護性。

    S 在 SOLID 中代表單一職責原則,即一個類應該只負責一項職責,這個類提供的所有服務都應該只為它負責的職責服務。

    使用基於欄位的依賴註入,高頻使用的類隨著時間的推移,我們會在類中逐漸添加越來越多的依賴項,我們用著很爽,很容易忽略類中的依賴已經太多了。但是如果使用基於建構函式的依賴註入,隨著越來越多的依賴項被添加到類中,建構函式會變得越來越大,我們一眼就可以察覺到哪裏不對勁。

    有一個有超過10個參數的建構函式是一個明顯的訊號,表明類已經轉變一個大而全的功能合集,需要將類分割成更小、更容易維護的塊。

    因此,盡管內容註入並不是破壞單一責任原則的直接原因,但它隱藏了訊號,使我們很容易忽略這些訊號。

    3.3 與依賴註入容器緊密耦合

    使用基於欄位的依賴註入的主要原因是為了避免 getter 和 setter 的樣板程式碼或為類建立建構函式。最後,這意味著設定這些欄位的唯一方法是透過Spring容器例項化類並使用反射註入它們,否則欄位將保持 null。

    依賴註入設計模式將類依賴項的建立與類本身分離開來,並將此責任轉移到類註入容器,從而允許程式設計解耦,並遵循單一職責和依賴項倒置原則(同樣可靠)。因此,透過自動裝配(autowiring)欄位來實作的類的解耦,最終會因為再次與類註入容器(在本例中是 Spring)耦合而遺失,從而使類在Spring容器之外變得無用。

    這意味著,如果您想在應用程式容器之外使用您的類,例如用於單元測試,您將被迫使用 Spring 容器來例項化您的類,因為沒有其他可能的方法(除了反射)來設定自動裝配欄位。

    3.4 隱藏依賴關系

    在使用依賴註入時,受影響的類應該使用公共介面清楚地公開這些依賴項,方法是在建構函式中公開所需的依賴項,或者使用方法(setter)公開可選的依賴項。當使用基於欄位的依賴註入時,實質上是將這些依賴對外隱藏了。

    總結

    我們已經看到,基於欄位的註入應該盡可能地避免,因為它有許多缺點,無論它看起來多麽優雅。推薦的方法是使用基於建構函式和基於setter的依賴註入。對於必需的依賴,建議使用基於建構函式的註入,設定它們為不可變的,並防止它們為 null。對於可選的依賴項,建議使用基於 setter 的註入。

    參考文件

    Field injection is not recommended – Spring IOC by Marc Nuri

    spring官方文件 1.4. Dependencies

    來源:juejin.cn/post/7275009721760432168

    >>

    END

    精品資料,超贊福利,免費領

    微信掃碼/長按辨識 添加【技術交流群

    群內每天分享精品學習資料

    最近開發整理了一個用於速刷面試題的小程式;其中收錄了上千道常見面試題及答案(包含基礎並行JVMMySQLRedisSpringSpringMVCSpringBootSpringCloud訊息佇列等多個型別),歡迎您的使用。

    👇👇

    👇點選"閱讀原文",獲取更多資料(持續更新中