先讓咱們來總結下,@Autowired的使用方式有哪些。根據文檔上的說明,@Autowired註解有三種經常使用方式。一種是在構造器的前面使用,後續咱們簡稱爲「constructor方式」;一種是在setter方法前面使用,後續簡稱爲「setter方式」;最後一種是直接在聲明的類屬性上使用,後續簡稱「field方式」 spring
Spring依賴注入的@Autowired總結一些想法。最近筆者看到一則實踐建言,建議Spring的依賴注入採用構造器的方式(下面會提到)。看到這條,難免心中會有疑惑,爲何? 工具
相信看過Spring依賴注入示例代碼、項目源碼的人,對筆者上面提到的三種方式不會陌生,應該都有所見聞,並且應該知道@Autowired默認是依據類型來進行注入的。既然提供了三種方式,爲何那條建言推薦使用constructor方式呢? 測試
@Controller
public class ItemStoreController{
private final UserService userService;
@Autowired
public ItemStoreController (UserService userService){
this.userService = userService;
}
//...省略
}
優點:
1.能夠將依賴的屬性設爲final,避免了不指望的可變性。 this
2.在寫測試用例時,這種方式的優點會更明顯。寫測試代碼時,依賴的屬性對象通常是經過mock實現的,可是脫離了Spring的依賴注入機制,如何將mock的對象進行賦值呢?經過構造器能夠很好的完成這項任務。寫過測試用例的人,應該對此很是贊同。但筆者對此不太苟同,假設採用了field方式,spring-test包如今提供了工具類能夠實現將mock的對象賦值給測試對象的屬性。 spa
劣勢: code
1. 沒法再次配置或再次注入,當指望再次注入bean時,則必須從新構造一個新的實例。這項跟上面的優點對比,自相矛盾了,具體還得看你的應用場景了。但筆者未想到須要再次注入的場景,在一篇博客中看到一句「Management through JMX MBeans is a compelling use case」,但願瞭解的朋友能夠指點一二。 對象
2. 若是當前類依賴的bean過多,那麼構造器就會變得很笨拙了。從表象上看,這項說的確實在理,但從另外一個角度來看,這項未必算是劣勢。假如當前類依賴了過多的bean,這個類是否須要從新審視一下,是否須要重構呢? 文檔
3. 存在循環依賴的風險。這點說的應該算戳中痛點了,若採用constructor方式,切記避免循環依賴。 源碼
@Controller
public class ItemStoreController{
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
//...省略
}
優點: 博客
1. 對比constructor方式,很明顯setter方式「重塑性」強。
2. 一樣能夠解決測試時綁定mock對象的問題。
3. 避免了依賴bean太多致使的構造器笨拙的現象。
劣勢:
1. 假設代碼的應用場景渴望不可變性的話,那麼setter方式天然暴露了太多。有人可能會提出,把依賴注入的屬性設爲final如何?既然你的本意不變,又暴露了可變的方法,豈不是本身打臉麼。
@Controller
public class ItemStoreController{
@Autowired
private UserService userService;
//...省略
}
優點:
1. 咋一看,是否是「清爽」了許多?能夠沒有專門的構造器和setter方法,直接註解在屬性上,簡單明瞭。
2. 避免了依賴bean太多致使的構造器笨拙的現象。但每每容易忽視了過多依賴致使的類結構的合理性,因此此項是優是劣,不是絕對的。
劣勢:
1. 寫測試用例時沒法直接綁定mock的依賴對象。但spring-test包中能夠解決這個問題了。
2. 沒有「重塑性」。
3. 綜上所述,@Autowired的三種用法其實沒有所謂的孰優孰劣,筆者也就不在此提倡哪一種用法被噴了。使用者須要根據具體的應用場景,例如可變性的要求、「重塑性」的須要、測試時的方便、代碼結構合理性等等因素吧,採用適合本身的方式。
4. 筆者在作上述內容的思考時,想到了另一個「話題」,不在本篇中敘述了,否則有些跑題。能夠先拋個引子,在後續博文中探討。「假設採用field方式注入bean,又想保證不可變性的話,可否把屬性設爲final呢?」