Spring注解依赖注入的三种方式的优缺点以及优先选择
當(dāng)我們?cè)谑褂靡蕾囎⑷氲臅r(shí)候,通常有三種方式:
1.通過構(gòu)造器來注入;
2.通過setter方法來注入;
3.通過filed變量來注入;
那么他們有什么區(qū)別嗎?應(yīng)該選擇哪種方式更好?
?
代碼示例:
Constructor
1 private DependencyA dependencyA; 2 private DependencyB dependencyB; 3 private DependencyC dependencyC; 4 5 @Autowired 6 public DI(DependencyA dependencyA, DependencyB dependencyB, DependencyC dependencyC) { 7 this.dependencyA = dependencyA; 8 this.dependencyB = dependencyB; 9 this.dependencyC = dependencyC; 10 }Setter
1 private DependencyA dependencyA; 2 private DependencyB dependencyB; 3 private DependencyC dependencyC; 4 5 @Autowired 6 public void setDependencyA(DependencyA dependencyA) { 7 this.dependencyA = dependencyA; 8 } 9 10 @Autowired 11 public void setDependencyB(DependencyB dependencyB) { 12 this.dependencyB = dependencyB; 13 } 14 15 @Autowired 16 public void setDependencyC(DependencyC dependencyC) { 17 this.dependencyC = dependencyC; 18 }Field
1 @Autowired 2 private DependencyA dependencyA; 3 4 @Autowired 5 private DependencyB dependencyB; 6 7 @Autowired 8 private DependencyC dependencyC;?
?
三種方式的區(qū)別小結(jié):
1.基于constructor的注入,會(huì)固定依賴注入的順序;該方式不允許我們創(chuàng)建bean對(duì)象之間的循環(huán)依賴關(guān)系,這種限制其實(shí)是一種利用構(gòu)造器來注入的益處 - 當(dāng)你甚至沒有注意到使用setter注入的時(shí)候,Spring能解決循環(huán)依賴的問題;
2.基于setter的注入,只有當(dāng)對(duì)象是需要被注入的時(shí)候它才會(huì)幫助我們注入依賴,而不是在初始化的時(shí)候就注入;另一方面如果你使用基于constructor注入,CGLIB不能創(chuàng)建一個(gè)代理,迫使你使用基于接口的代理或虛擬的無參數(shù)構(gòu)造函數(shù)。
3.相信很多同學(xué)都選擇使用直接在成員變量上寫上注解來注入,正如我們所見,這種方式看起來非常好,精短,可讀性高,不需要多余的代碼,也方便維護(hù);
?
缺點(diǎn):
1.當(dāng)我們利用constructor來注入的時(shí)候,比較明顯的一個(gè)缺點(diǎn)就是:假如我們需要注入的對(duì)象特別多的時(shí)候,我們的構(gòu)造器就會(huì)顯得非常的冗余、不好看,非常影響美觀和可讀性,維護(hù)起來也較為困難;
2.當(dāng)我們選擇setter方法來注入的時(shí)候,我們不能將對(duì)象設(shè)為final的;
3.當(dāng)我們?cè)趂ield變量上來實(shí)現(xiàn)注入的時(shí)候
? ? a.這樣不符合JavaBean的規(guī)范,而且很有可能引起空指針;
? ? b.同時(shí)也不能將對(duì)象標(biāo)為final的;
c.類與DI容器高度耦合,我們不能在外部使用它;
? ? d.類不通過反射不能被實(shí)例化(例如單元測試中),你需要用DI容器去實(shí)例化它,這更像集成測試;
? ? ... etc.
?
來自Spring官方文檔的建議:??
在Spring 3.x 中,Spring團(tuán)隊(duì)建議我們使用setter來注入:
大致是說大量的構(gòu)造器參數(shù)會(huì)顯得非常笨重,尤其是當(dāng)屬性是可選的時(shí)候。setter方法可以使類的對(duì)象在后來重新配置或者重新注入。提供所有的依賴意味著對(duì)象總是返回一個(gè)完全初始化狀態(tài)的client客戶端(調(diào)用)。缺點(diǎn)是對(duì)象變得不那么適合重新配置和重新注入。
?
而在Spring 4.x 中,Spring團(tuán)隊(duì)不再建議我們使用setter來注入,改為了constructor:
Spring團(tuán)隊(duì)通常建議使用構(gòu)造器來注入,因?yàn)樗试S一個(gè)應(yīng)用程序組件實(shí)現(xiàn)為不可變對(duì)象,并確保所需的依賴項(xiàng)不是空。此外構(gòu)造器注入組件總是返回一個(gè)完全初始化狀態(tài)的client客戶端(調(diào)用)。附注,大量的構(gòu)造函數(shù)參數(shù)是一個(gè)糟糕的代碼習(xí)慣,看起來也很壞,這意味著類可能有太多的責(zé)任,應(yīng)該被重構(gòu),以更好地解決適當(dāng)?shù)年P(guān)注點(diǎn)分離。
setter方法只應(yīng)該主要的用在可以在類中指定合理的默認(rèn)值的可選的依賴關(guān)系。否則,用到依賴的所有地方都應(yīng)該進(jìn)行非空檢查。setter注入的一個(gè)好處是,setter方法使類的對(duì)象可以在之后重新配置或者重新注入。
(以上是本人的渣渣英語翻譯結(jié)合有道得來。。大佬看到請(qǐng)輕噴)
?
接下來插播一條Spring 4.3 的新特征:
在Spring 4.3 以后,如果我們的類中只有單個(gè)構(gòu)造函數(shù),那么Spring就會(huì)實(shí)現(xiàn)一個(gè)隱式的自動(dòng)注入,上代碼:
之前:
1 @Service 2 public class FooService { 3 4 private final FooRepository repository; 5 6 @Autowired 7 public FooService(FooRepository repository) { 8 this.repository = repository 9 } 10 }在Spring 4.3 之后:
1 @Service 2 public class FooService { 3 4 private final FooRepository repository; 5 6 public FooService(FooRepository repository) { 7 this.repository = repository 8 } 9 }如我們所見,我去掉了構(gòu)造器上的@Autowired注解,經(jīng)測試后發(fā)現(xiàn),程序能正常運(yùn)行,repository的依賴也被成功注入了,當(dāng)時(shí)感覺就很amazing。。有興趣的同學(xué)可以試試~
?
總結(jié):
1.強(qiáng)制性的依賴性或者當(dāng)目標(biāo)不可變時(shí),使用構(gòu)造函數(shù)注入(應(yīng)該說盡量都使用構(gòu)造器來注入)
2.可選或多變的依賴使用setter注入(建議可以使用構(gòu)造器結(jié)合setter的方式來注入)
3.在大多數(shù)的情況下避免field域注入(感覺大多數(shù)同學(xué)可能會(huì)有異議,畢竟這個(gè)方式寫起來非常簡便,但是它的弊端確實(shí)遠(yuǎn)大于這些優(yōu)點(diǎn))
4.Spring 4.3+ 的同學(xué)可以試一試構(gòu)造器的隱式注入,采用此方式注入后,使得我們的代碼更優(yōu)雅,更獨(dú)立,減少了對(duì)Spring的依賴性。
?
ps: 轉(zhuǎn)載請(qǐng)標(biāo)注出處謝謝。
轉(zhuǎn)載于:https://www.cnblogs.com/chansblogs/p/8343930.html
總結(jié)
以上是默认站点為你收集整理的Spring注解依赖注入的三种方式的优缺点以及优先选择的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到拿刀砍人不见血是什么预兆
- 下一篇: JSP中直接在输入框中校验