juejin.cn/post/6844904064212271117
介紹今天使用Idea寫程式碼的時候,看到之前的專案中顯示有warning的提示,去看了下,是如下程式碼?
@Autowireprivate JdbcTemplate jdbcTemplate;
提示的警告資訊
Field injection is not recommended Inspection info: Spring Team recommends: "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies".
這段是Spring工作組的建議,大致翻譯一下:
屬性欄位注入的方式不推薦,檢查到的問題是:Spring團隊建議:"始終在bean中使用基於建構函式的依賴項注入,始終對強制性依賴項使用斷言"
如圖
Field注入警告
注入方式雖然當前有關Spring Framework(5.0.3)的文件僅定義了兩種主要的注入型別,但實際上有三種:
基於建構函式的依賴注入
public class UserServiceImpl implents UserService{ private UserDao userDao; @Autowire public UserServiceImpl(UserDao userDao){ this.userDao = userDao; }}
基於Setter的依賴注入
public class UserServiceImpl implents UserService{ private UserDao userDao; @Autowire public serUserDao(UserDao userDao){ this.userDao = userDao; } }
基於欄位的依賴注入
public class UserServiceImpl implents UserService{ @Autowire private UserDao userDao; }
基於欄位的依賴注入方式會在Idea當中吃到黃牌警告,但是這種使用方式使用的也最廣泛,因為簡潔方便.您甚至可以在一些Spring指南中看到這種注入方法,儘管在文件中不建議這樣做.(有點執法犯法的感覺)
Spring註解:超級全面的 SpringBoot 註解介紹
如圖
Spring自己的文件
基於欄位的依賴注入缺點對於有final修飾的變數不好使
Spring的IOC對待屬性的注入使用的是set形式,但是final型別的變數在呼叫class的建構函式的這個過程當中就得初始化完成,這個是基於欄位的依賴注入做不到的地方.只能使用基於建構函式的依賴注入的方式
掩蓋單一職責的設計思想
我們都知道在OOP的設計當中有一個單一職責思想,如果你採用的是基於建構函式的依賴注入的方式來使用Spring的IOC的時候,當你注入的太多的時候,這個構造方法的引數就會很龐大,類似於下面.
當你看到這個類的構造方法那麼多引數的時候,你自然而然的會想一下:這個類是不是違反了單一職責思想?.但是使用基於欄位的依賴注入不會讓你察覺,你會很沉浸在@Autowire當中
public class VerifyServiceImpl implents VerifyService{ private AccountService accountService; private UserService userService; private IDService idService; private RoleService roleService; private PermissionService permissionService; private EnterpriseService enterpriseService; private EmployeeService employService; private TaskService taskService; private RedisService redisService; private MQService mqService; public SystemLogDto(AccountService accountService, UserService userService, IDService idService, RoleService roleService, PermissionService permissionService, EnterpriseService enterpriseService, EmployeeService employService, TaskService taskService, RedisService redisService, MQService mqService) { this.accountService = accountService; this.userService = userService; this.idService = idService; this.roleService = roleService; this.permissionService = permissionService; this.enterpriseService = enterpriseService; this.employService = employService; this.taskService = taskService; this.redisService = redisService; this.mqService = mqService; }}
與Spring的IOC機制緊密耦合
當你使用基於欄位的依賴注入方式的時候,確實可以省略構造方法和setter這些個模板型別的方法,但是,你把控制權全給Spring的IOC了,別的類想重新設定下你的某個注入屬性,沒法處理(當然反射可以做到).
本身Spring的目的就是解藕和依賴反轉,結果透過再次與類注入器(在本例中為Spring)耦合,失去了透過自動裝配類欄位而實現的對類的解耦,從而使類在Spring容器之外無效.
隱藏依賴性
當你使用Spring的IOC的時候,被注入的類應當使用一些public型別(構造方法,和setter型別方法)的方法來向外界表達:我需要什麼依賴.但是基於欄位的依賴注入的方式,基本都是private形式的,private把屬性都給封印到class當中了.
無法對注入的屬性進行安檢
基於欄位的依賴注入方式,你在程式啟動的時候無法拿到這個類,只有在真正的業務使用的時候才會拿到,一般情況下,這個注入的都是非null的,萬一要是null怎麼辦,在業務處理的時候錯誤才爆出來,時間有點晚了,如果在啟動的時候就暴露出來,那麼bug就可以很快得到修復(當然你可以加註解校驗).
如果你想在屬性注入的時候,想根據這個注入的物件操作點東西,你無法辦到.我碰到過的例子:一些配置資訊啊,有些人總是會配錯誤,等到了自己測試業務階段才知道配錯了,例如執行緒初始個數不小心配置成了3000,機器真的是狂叫啊!這個時候就需要再某些Value注入的時候做一個檢測機制.
結論透過上面,我們可以看到,基於欄位的依賴注入方式有很多缺點,我們應當避免使用基於欄位的依賴注入.推薦的方法是使用基於建構函式和基於setter的依賴注入.對於必需的依賴項,建議使用基於建構函式的注入,以使它們成為不可變的,並防止它們為null。對於可選的依賴項,建議使用基於Setter的注入
後記翻譯自field-injection-is-not-recommended,加入了自己的白話理解!