10.19 你可能使用了Spring最不推薦的註解方式

前些天新加入項目中的小夥兒寫了一段代碼,我看到之後,頓時以固有的經驗來判斷說:Spring的註解不能這樣寫,不夠簡潔云云。但本著對技術的鑽研精神,還是深入分析比較了一下Spring的註解形式及優缺點。原來,大家最常用的註解方式不是最優的,而是最不推薦的。

你可能使用了Spring最不推薦的註解方式

前言

使用Spring框架最核心的兩個功能就是IOC和AOP。IOC也就是控制反轉,我們將類的實例化、依賴關係等都交由Spring來處理,以達到解耦合、利用複用、利於測試、設計出更優良程序的目的。而對用戶來說,操作最對的便是註解。在Spring中提供了三類註解方式,下面我們就逐一分析。最後,你會發現,你最常用、看起來最方便的形式確實最不推薦的一種形式。

常見的注入方式

Field注入

@Controller
public class FooController {
@Autowired
// @Resource
private FooService fooService;
}

此種註解方式,應用最廣泛:

注入簡單,只需在字段上添加@Autowired或@Resource;

減少大量冗餘代碼,美觀;

新增Field時不需要過多代碼修改;

構造函數注入

@Controller
public class FooController {
private final FooService fooService;
private final FooService1 fooService1;
@Autowired
public FooController(FooService fooService,FooService1 fooService1) {
this.fooService = fooService;
this.fooService1 = fooService1;
}
}

@Controller
public class FooController {
private final FooService fooService;
// 當只有一個參數時可不寫@Autowired
public FooController(FooService fooService) {
this.fooService = fooService;
}
}

Spring4.x推薦的注入方式。對比Field注入:

  • 代碼臃腫
  • 新增Field修改麻煩
  • 當Field多餘5個時不符合構造方法的基本規範,顯得笨重、臃腫;

setter注入

@Controller 

public class FooController {
private FooService fooService;
@Autowired
public void setFooService(FooService fooService) {
this.fooService = fooService;
}
}

Spring3.x推薦的注入方式,但並沒有被廣泛應用,當初推薦的理由:

  • 解決了構造器注入的笨重;
  • 可以讓類在之後重新配置或者重新注入。

為什麼Spring4.x推薦構造函數注入

在上面的分析看來,構造函數注入好像並沒有顯現出來它的優勢,但問什麼Spring4.x會推翻之前推薦的setter注入,採用構造函數注入呢?官方的理由彙總如下:

  • 依賴不可變:加入了final來約束脩飾Field,這條是很顯然的;
  • 依賴不可為空:在實例化的時候會檢查構造函數參數是否為空,如果為空(未找到改類型的實例對象)則會拋出異常。
  • 單一職責:當使用構造函數注入時,如果參數過多,你會發現當前類的職責過大,需要進行拆分。而使用Field注入時,你並不會意識到此問題。
  • 更利於單元測試:按照其他兩種方式注入,當單元測試時需要初始化整個spring的環境,而採用構造方法注入時,只需要初始化需要的類即可,即可以直接實例化需要的類。
  • 避免IOC容器以外環境調用時潛在的NPE(空指針異常)。
  • 避免循環依賴。
  • 保證返回客戶端(調用)的代碼的時候是完全初始化的狀態。

疑問

如果有大量依賴需要注入,怎麼辦?

如果有大量依賴需要注入說明該類的職責過於複雜,需要遵從單一性原則進行拆分;

其他注入方式是否合理?

存在即合理,根據具體情況可以採用最適合的方式。比如,可以同時使用@Qualifier來達到一些約束限定的目的。也可以使用setter注入和構造函數注入相結合的方式來進行注入。


分享到:


相關文章: