在使用Idea中通過註解注入欄位時是否遇見過這樣一個提示:
Field injection is not recommended(不推薦使用欄位注入)
一. 什麼是欄位注入,Spring中依賴注入的方式有哪些?
在Spring中依賴注入有三大類:欄位注入、構造器注入、Setter方法注入。
欄位注入是將Bean作為欄位注入到類中,也是最方便,用的最多的注入方式。
二. 官方為什麼不推薦使用欄位注入
首先來看欄位注入
@RestController
public class TestHandleController {
@Autowired
TestHandleService testHandleService;
public void helloTestService(){
testHandleService.hello();
}
}
欄位注入的非常的簡便,通過以上程式碼我們就可以輕鬆的使用TestHandleService類,但是如果變成下面這樣呢:
TestHandleController testHandle = new TestHandleController();
testHandle.helloTestService();
這樣執行結果為空指標異常,這就是欄位注入的第一個問題:物件的外部可見性,無法在容器外部例項化TestHandleService,類和容器的耦合度過高,無法脫離容器訪問目標物件。
接下來看第二段程式碼:
public class TestA(){
@Autowired
private TestB testB;
}
public class TestB(){
@Autowired
private TestA testA;
}
這段程式碼在idea中不會報任何錯誤,但是當你啟動專案時會發現報錯,大致意思是:建立Bean失敗,原因是當前Bean已經作為迴圈引用的一部分注入到了其他Bean中。
這就是欄位注入的第二個問題:可能導致迴圈依賴
欄位注入還有第三個問題:無法設定注入的物件為final,也無法注入靜態變數,原因是變數必須在類例項化進行初始化。
整理一下,欄位注入可能引起的三個問題:
1. 物件的外部可見性
2. 可能導致迴圈依賴
3. 無法設定注入的物件為final,也無法注入靜態變數
接下來看構造器注入--官方推薦的注入方式
使用形式也很簡單:
private TestHandleService testHandleService;
@Autowired
public TestHandleController(TestHandleService testHandleService){
this.testHandleService = testHandleService;
}
通過構造器的方式將Bean注入到欄位中。
構造器注入能夠保證注入的元件不可變,並且確保需要的依賴不為空。
這樣就可以將變數設定為final,並且傳遞的肯定是一個物件,避免出現空指標異常。
若是出現欄位注入中迴圈依賴的問題,在專案啟動時Spring會非常形象的將錯誤丟擲來:
Description:
The dependencies of some of the beans in the application context form a cycle:
testContrtoller (field private com.example.designstudy.service.TestService com.example.designstudy.controller.TestContrtoller.testService)
┌─────┐
| testService defined in file [D:\design-study\target\classes\com\example\designstudy\service\TestService.class]
↑ ↓
| testHandleServiceImpl defined in file [D:\design-study\target\classes\com\example\designstudy\service\impl\TestHandleServiceImpl.class]
└─────┘
顯而易見的發現錯誤的地方。
由此可見,欄位注入的三大問題都能解決,但是構造器注入就沒有其他問題了嗎?
答案肯定是否定的,當依賴的物件很多時,需要嚴格按照構造器的順序去填寫依賴的物件,這將導致程式碼可讀性和可維護性變得很差。
這時候可以引入Setter方法進行注入,Setter方法和構造器注入很像,不過Setter更具有可讀性。
並且使用Setter方法注入可以實現按需注入,不使用的物件不需要想構造器注入一樣強制注入。
總結一下三種注入方式:
構造器注入適用於強制物件注入
Setter注入適合可選物件注入
欄位注入方式應該儘量避免,因為物件無法脫離容器獨立執行(話雖這麼說,但我還是欄位注入用得多,因為方便啊 [/狗頭])