當前位置: 妍妍網 > 碼農

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

2024-05-31碼農

大家好,我是磊哥。

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

說明

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

Field injection is not recommended

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

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

依賴註入的型別

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

  • 基於建構函式的依賴註入

  • 基於setter的依賴註入

  • 基於欄位的依賴註入

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

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

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

    @Componentpublic classConstructorBasedInjection{privatefinal InjectedBean injectedBean;@AutowiredpublicConstructorBasedInjection(InjectedBean injectedBean){this.injectedBean = injectedBean; }}

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

    public classSimpleMovieLister {// the SimpleMovieLister has a dependency on a MovieFinderprivate MovieFinder movieFinder;// a constructor so that the Spring container can inject a MovieFinderpublicSimpleMovieLister(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方法。

    @Componentpublic classSetterBasedInjection{private InjectedBean injectedBean;@AutowiredpublicvoidsetInjectedBean(InjectedBean injectedBean){this.injectedBean = injectedBean; }}

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

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

    2.3 基於內容的依賴註入

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

    @Componentpublic classFieldBasedInjection{@Autowiredprivate InjectedBean injectedBean;}

    正如所看到的,這是依賴註入最幹凈的方法,因為它避免了添加樣板程式碼,並且不需要聲明類的建構函式。程式碼看起來很幹凈簡潔,但是正如程式碼檢查器已經向我們暗示的那樣,這種方法有一些缺點。更多類似面試資料,公眾 號Java精選,回復java面試,獲取面試資料,支持線上刷題。

    基於欄位的依賴註入缺陷

    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。對於可選的依賴項,建議使用基於sett的註入。

    🔥 磊哥私藏精品 熱門推薦 🔥