哦哇資訊網

面試突擊77:Spring 依賴注入有幾種?各有什麼優缺點?

由 磊哥聊程式設計 發表于 美食2023-01-05

IoC 和 DI 是 Spring 中最重要的兩個概念,其中 IoC(Inversion of Control)為控制反轉的思想,而 DI(Dependency Injection)依賴注入為其(IoC)具體實現。那麼 DI 實現依賴注入的方式有幾種?這些注入方式又有什麼不同?接下來,我們一起來看。

0。概述

在 Spring 中實現依賴注入的常見方式有以下 3 種:

屬性注入(Field Injection);

Setter 注入(Setter Injection);

構造方法注入(Constructor Injection)。

它們的具體使用和優缺點分析如下。

1。屬性注入

屬性注入是我們最熟悉,也是日常開發中使用最多的一種注入方式

,它的實現程式碼如下:

@RestControllerpublic class UserController { // 屬性物件 @Autowired private UserService userService; @RequestMapping(“/add”) public UserInfo add(String username, String password) { return userService。add(username, password); }}

1。1 優點分析

屬性注入最大的優點就是實現簡單、使用簡單

,只需要給變數上新增一個註解(@Autowired),就可以在不 new 物件的情況下,直接獲得注入的物件了(這就是 DI 的功能和魅力所在),所以它的優點就是使用簡單。

1。2 缺點分析

然而,屬性注入雖然使用簡單,但也存在著很多問題,甚至編譯器 Idea 都會提醒你“不建議使用此注入方式”,Idea 的提示資訊如下:

屬性注入的缺點主要包含以下 3 個:

功能性問題:無法注入一個不可變的物件(final 修飾的物件);

通用性問題:只能適應於 IoC 容器;

設計原則問題:更容易違背單一設計原則。

接下來我們一一來看。

缺點1:功能性問題

使用屬性注入無法注入一個不可變的物件(final 修飾的物件)

,如下圖所示:

原因也很簡單:

在 Java 中 final 物件(不可變)要麼直接賦值,要麼在構造方法中賦值,所以當使用屬性注入 final 物件時,它不符合 Java 中 final 的使用規範,所以就不能注入成功了。

PS:如果要注入一個不可變的物件,要怎麼實現呢?使用下面的構造方法注入即可。

缺點2:通用性問題

使用屬性注入的方式只適用於 IoC 框架(容器)

,如果將屬性注入的程式碼移植到其他非 IoC 的框架中,那麼程式碼就無效了,所以屬性注入的通用性不是很好。

缺點3:設計原則問題

使用屬性注入的方式,因為使用起來很簡單,所以開發者很容易在一個類中同時注入多個物件,而這些物件的注入是否有必要?是否符合程式設計中的單一職責原則?就變成了一個問題。

但可以肯定的是,

注入實現越簡單,那麼濫用它的機率也越大,所以出現違背單一職責原則的機率也越大

注意:

這裡強調的是違背設計原則(單一職責)的可能性,而不是一定會違背設計原則

,二者有著本質的區別。

2。Setter 注入

Setter 注入的實現程式碼如下:

@RestControllerpublic class UserController { // Setter 注入 private UserService userService; @Autowired public void setUserService(UserService userService) { this。userService = userService; } @RequestMapping(“/add”) public UserInfo add(String username, String password) { return userService。add(username, password); }}

優缺點分析

從上面程式碼可以看出,Setter 注入比屬性注入要麻煩很多。

要說 Setter 注入有什麼優點的話,那麼首當其衝的就是它完全符合單一職責的設計原則,因為每一個 Setter 只針對一個物件

但它的缺點也很明顯,它的缺點主要體現在以下 2 點:

不能注入不可變物件(final 修飾的物件);

注入的物件可被修改。

接下來我們一一來看。

缺點1:不能注入不可變物件

使用 Setter 注入依然不能注入不可變物件,比如以下注入會報錯:

缺點2:注入物件可被修改

Setter 注入提供了 setXXX 的方法,意味著你可以在任何時候、在任何地方,透過呼叫 setXXX 的方法來改變注入物件,所以

Setter 注入的問題是,被注入的物件可能隨時被修改

3。構造方法注入

構造方法注入是 Spring 官方從 4.x 之後推薦的注入方式

,它的實現程式碼如下:

@RestControllerpublic class UserController { // 構造方法注入 private UserService userService; @Autowired public UserController(UserService userService) { this。userService = userService; } @RequestMapping(“/add”) public UserInfo add(String username, String password) { return userService。add(username, password); }}

當然,

如果當前的類中只有一個構造方法,那麼 @Autowired 也可以省略

,所以以上程式碼還可以這樣寫:

@RestControllerpublic class UserController { // 構造方法注入 private UserService userService; public UserController(UserService userService) { this。userService = userService; } @RequestMapping(“/add”) public UserInfo add(String username, String password) { return userService。add(username, password); }}

優點分析

構造方法注入相比於前兩種注入方法,它可以注入不可變物件,並且它只會執行一次,也不存在像 Setter 注入那樣,被注入的物件隨時被修改的情況,它的優點有以下 4 個:

可注入不可變物件;

注入物件不會被修改;

注入物件會被完全初始化;

通用性更好。

接下來我們一一來看。

優點1:注入不可變物件

使用構造方法注入可以注入不可變物件,如下程式碼所示:

優點2:注入物件不會被修改

構造方法注入不會像 Setter 注入那樣,

構造方法在物件建立時只會執行一次,因此它不存在注入物件被隨時(呼叫)修改的情況。

優點3:完全初始化

因為依賴物件是在構造方法中執行的,而構造方法是在物件建立之初執行的,因此被注入的物件在使用之前,會被完全初始化,這也是構造方法注入的優點之一。

優點4:通用性更好

構造方法和屬性注入不同,構造方法注入可適用於任何環境,無論是 IoC 框架還是非 IoC 框架,構造方法注入的程式碼都是通用的,所以它的通用性更好。

總結

依賴注入的常見實現方式有 3 種:屬性注入、Setter 注入和構造方法注入。其中屬性注入的寫法最簡單,所以日常專案中使用的頻率最高,但它的通用性不好;而 Spring 官方推薦的是構造方法注入,它可以注入不可變物件,其通用性也更好,如果是注入可變物件,那麼可以考慮使用 Setter 注入。

參考 & 鳴謝

Spring 官方文件

TAG: 注入構造方法物件UserServicesetter