Spring的@Autowired實踐感知

其實在工做中使用了Spring這麼久,有不少的細節是值得使用者去思考的。如今筆者想針對Spring依賴注入的@Autowired總結一些想法。最近筆者看到一則實踐建言,建議Spring的依賴注入採用構造器的方式(下面會提到)。看到這條,難免心中會有疑惑,爲何?spring

@Autowired的多種方式

先讓咱們來總結下,@Autowired的使用方式有哪些。根據文檔上的說明,@Autowired註解有三種經常使用方式。一種是在構造器的前面使用,後續咱們簡稱爲「constructor方式」;一種是在setter方法前面使用,後續簡稱爲「setter方式」;最後一種是直接在聲明的類屬性上使用,後續簡稱「field方式」。wordpress

相信看過Spring依賴注入示例代碼、項目源碼的人,對筆者上面提到的三種方式不會陌生,應該都有所見聞,並且應該知道@Autowired默認是依據類型來進行注入的。既然提供了三種方式,爲何那條建言推薦使用constructor方式呢?工具

各個方式的對比

筆者查閱了幾篇相關的歪果仁所寫的博客及帖子,其實能夠發現不少人對這三種方式的對比和取捨早已爭論不休,筆者大體總結了幾方面。測試

constructor方式

@Service
public ProductionService {
	private final UserService userService;

	@Autowired
	public ProductionService(UserService userService){
		this.userService = userService;
	}

	//...省略
}

優點:this

  1. 能夠將依賴的屬性設爲final,避免了不指望的可變性。
  2. 在寫測試用例時,這種方式的優點會更明顯。寫測試代碼時,依賴的屬性對象通常是經過mock實現的,可是脫離了Spring的依賴注入機制,如何將mock的對象進行賦值呢?經過構造器能夠很好的完成這項任務。寫過測試用例的人,應該對此很是贊同。但筆者對此不太苟同,假設採用了field方式,spring-test包如今提供了工具類能夠實現將mock的對象賦值給測試對象的屬性。

劣勢:.net

  1. 沒法再次配置或再次注入,當指望再次注入bean時,則必須從新構造一個新的實例。這項跟上面的優點對比,自相矛盾了,具體還得看你的應用場景了。但筆者未想到須要再次注入的場景,在一篇博客中看到一句「Management through JMX MBeans is a compelling use case」,但願瞭解的朋友能夠指點一二。
  2. 若是當前類依賴的bean過多,那麼構造器就會變得很笨拙了。從表象上看,這項說的確實在理,但從另外一個角度來看,這項未必算是劣勢。假如當前類依賴了過多的bean,這個類是否須要從新審視一下,是否須要重構呢?
  3. 存在循環依賴的風險。這點說的應該算戳中痛點了,若採用constructor方式,切記避免循環依賴。

setter方式

@Service
public ProductionService {
	private UserService userService;

	@Autowired
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	
	//...省略
}

優點:code

  1. 對比constructor方式,很明顯setter方式「重塑性」強。
  2. 一樣能夠解決測試時綁定mock對象的問題。
  3. 避免了依賴bean太多致使的構造器笨拙的現象。

劣勢:對象

  1. 假設代碼的應用場景渴望不可變性的話,那麼setter方式天然暴露了太多。有人可能會提出,把依賴注入的屬性設爲final如何?既然你的本意不變,又暴露了可變的方法,豈不是本身打臉麼。

field方式

@Service
public ProductionService {
	@Autowired
	private UserService userService;
	
	//...省略
}

優點:文檔

  1. 咋一看,是否是「清爽」了許多?能夠沒有專門的構造器和setter方法,直接註解在屬性上,簡單明瞭。
  2. 避免了依賴bean太多致使的構造器笨拙的現象。但每每容易忽視了過多依賴致使的類結構的合理性,因此此項是優是劣,不是絕對的。

劣勢:get

  1. 寫測試用例時沒法直接綁定mock的依賴對象。但spring-test包中能夠解決這個問題了。
  2. 沒有「重塑性」。

綜上所述,@Autowired的三種用法其實沒有所謂的孰優孰劣,筆者也就不在此提倡哪一種用法被噴了。使用者須要根據具體的應用場景,例如可變性的要求、「重塑性」的須要、測試時的方便、代碼結構合理性等等因素吧,採用適合本身的方式。

筆者在作上述內容的思考時,想到了另一個「話題」,不在本篇中敘述了,否則有些跑題。能夠先拋個引子,在後續博文中探討。「假設採用field方式注入bean,又想保證不可變性的話,可否把屬性設爲final呢?」

參考

  • I was wrong: Constructor vs. setter injection

https://steveschols.wordpress.com/2012/06/05/i-was-wrong-constructor-vs-setter-injection/

  • Why I Changed My Mind About Field Injection?

http://www.petrikainulainen.net/software-development/design/why-i-changed-my-mind-about-field-injection/

  • Why field injection is evil

http://olivergierke.de/2013/11/why-field-injection-is-evil/

相關文章
相關標籤/搜索