今天在看項目代碼的時候發如今依賴注入的時候使用了構造器注入,以前使用過 Field 注入和 Setter 方法注入,對構造器注入不是很瞭解。通過查閱資料看到,Spring 推薦使用構造器注入的方式,下面介紹構造器注入到底有什麼玄機。html
@Controller public class HelloController { @Autowired private AlphaService alphaService; @Autowired private BetaService betaService; }
field 注入方式是使用最多的,緣由是這種方式使用起來很是簡單,代碼更加簡潔。java
@Controller public class HelloController { private AlphaService alphaService; private BetaService betaService; @Autowired public void setAlphaService(AlphaService alphaService) { this.alphaService = alphaService; } @Autowired public void setBetaService(BetaService betaService) { this.betaService = betaService; } }
在 Spring 3.x 剛推出的時候,Spring 官方在對比構造器注入和 Setter 注入時,推薦使用 Setter 方法注入:spring
Spring 3.x Constructor-based or setter-based DI?app
The Spring team generally advocates setter injection, because large numbers of constructor arguments can get unwieldy, especially when properties are optional. Setter methods also make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is a compelling use case.less
Some purists favor constructor-based injection. Supplying all object dependencies means that the object is always returned to client (calling) code in a totally initialized state. The disadvantage is that the object becomes less amenable to reconfiguration and re-injection.ide
意思是說,當出現不少注入項的時候,構造器參數可能會變得臃腫,特別是當參數時可選的時候。Setter 方式注入可讓類在以後從新配置和從新注入;函數
@Controller public class HelloController { private final AlphaService alphaService; private final BetaService betaService; @Autowired public HelloController(AlphaService alphaService, BetaService betaService) { this.alphaService = alphaService; this.betaService = betaService; } }
Spring 4.x 的時候,Spring 官方在對比構造器注入和 Setter 注入時,推薦使用構造器注入方式:ui
Spring 4.x Constructor-based or setter-based DI?this
The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not
null
. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.codeSetter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.
由於使用構造器注入方式注入的組件不可變,且保證了須要的依賴不爲 null。此外,構造器注入的組件老是可以在徹底初始化的狀態返回給客戶端(調用方);對於不少參數的構造器說明可能包含了太多了職責,違背了單一職責原則,表示代碼應該重構來分離職責到合適的地方。
在對比 Setter 方法注入和 構造器注入的時候 分別引用的 Spring 官方文檔的第二段闡述了除推薦方式的另外一種方式的特色。
在 Spring 3.x 的時候 Spring 推薦 Setter 方法注入,第二段表示:一些純粹主義者喜歡基於構造函數的注入。提供全部對象依賴項意味着對象老是在徹底初始化狀態下返回給客戶機(調用)代碼。缺點是對象不太容易從新配置和從新注入。
在 Spring 4.x 的時候 Spring 推薦構造器注入,第二段表示:Setter 注入應該主要用於可選的依賴項,這些依賴項能夠在類中分配合理的默認值。不然,必須在代碼使用依賴項的任何地方執行非空檢查。setter 注入的一個好處是,setter 方法使該類的對象可以在之後從新配置或從新注入。
Setter 注入應該被用於可選依賴項。當沒有提供它們時,類應該可以正常工做。在對象被實例化以後,依賴項能夠在任什麼時候候被更改。
構造器注入有利於強制依賴。經過在構造函數中提供依賴,您能夠確保依賴對象在被構造時已準備好被使用。在構造函數中賦值的字段也能夠是final的,這使得對象是徹底不可變的,或者至少能夠保護其必需的字段。
構造器注入還能夠避免 Field 注入的循環依賴問題,好比 在 Alpha 中注入 Beta,又在 Beta 中注入 Alpha。若是使用構造器注入,在 Spring 啓動的時候就會拋出 BeanCurrentlyInCreationException 提醒循環依賴。
參考:
https://www.vojtechruzicka.com/field-dependency-injection-considered-harmful/