1. 實(shí)例的注入方式
首先來看看 Spring 中的實(shí)例該如何注入咧虎,總結(jié)起來土辩,無非三種:
- 屬性注入
- set 方法注入
- 構(gòu)造方法注入
我們分別來看下幕垦。
1.1 屬性注入
屬性注入是大家最為常見也是使用最多的一種注入方式了,代碼如下:
@Service
public class BService {
@Autowired
AService aService;
//...
}
這里是使用 @Autowired 注解注入僚纷。另外也有 @Resource 以及 @Inject 等注解巨柒,都可以實(shí)現(xiàn)注入樱拴。
不過不知道小伙伴們有沒有留意過,在 IDEA 里邊洋满,使用屬性注入晶乔,會(huì)有一個(gè)警告??:
不推薦屬性注入!
原因我們后面討論牺勾。
1.2 set 方法注入
set 方法注入太過于臃腫正罢,實(shí)際上很少使用:
@Service
public class BService {
AService aService;
@Autowired
public void setaService(AService aService) {
this.aService = aService;
}
}
這代碼看一眼都覺得難受,堅(jiān)決不用驻民。
1.3 構(gòu)造方法注入
構(gòu)造方法注入方式如下:
@Service
public class AService {
BService bService;
@Autowired
public AService(BService bService) {
this.bService = bService;
}
}
如果類只有一個(gè)構(gòu)造方法翻具,那么 @Autowired 注解可以省略;如果類中有多個(gè)構(gòu)造方法回还,那么需要添加上 @Autowired 來明確指定到底使用哪個(gè)構(gòu)造方法裆泳,否則默認(rèn)使用無參構(gòu)造器。如若多個(gè)構(gòu)造器都未添加@Autowired 柠硕,同時(shí)又沒有定義無參構(gòu)造器工禾,則報(bào)錯(cuò)运提。
報(bào)錯(cuò)如下:No default constructor found; nested exception is java.lang.NoSuchMethodException: com.cjf.spring.circle.constructor.demo1.B.<init>()
2. 實(shí)例注入方式大 PK
上面給大家列出來了三種注入方式,那么三種注入方式各自有何區(qū)別呢闻葵?
結(jié)合 Spring 官方文檔民泵,我們來分析下。
松哥翻出了 12 年前的 Spring3.0 的文檔(https://docs.spring.io/spring-framework/docs/3.0.x/reference/beans.html)槽畔,里邊有如下一段話:
我來簡(jiǎn)單翻譯下(意譯):
使用構(gòu)造方法注入還是使用 set 方法注入栈妆?由于構(gòu)造方法注入和 set 方法注入可以混合使用,因此厢钧,如果需要強(qiáng)制注入鳞尔,我們可以使用構(gòu)造方法注入的方式;如果是可選注入早直,則我們可以使用 set 方法注入的方式铅檩。當(dāng)然,我們?cè)?setter 上使用 @Required 注解可以讓 set 方法注入也變?yōu)閺?qiáng)制性注入莽鸿。Spring 團(tuán)隊(duì)通常提倡 setter 注入,因?yàn)楫?dāng)屬性特別多的時(shí)候拾给,構(gòu)造方法看起來會(huì)特別臃腫祥得,特別是當(dāng)屬性是可選的時(shí)(屬性可選意味著沒必要通過構(gòu)造方法注入)。Setter 方法注入還有一個(gè)好處就是可以使該類的屬性可以在以后重新配置或重新注入蒋得。一些純粹主義者喜歡基于構(gòu)造函數(shù)的注入级及,這樣意味著所有的屬性都被初始化了,缺點(diǎn)則是對(duì)象變得不太適合重新配置和重新注入额衙。另外在一些特殊的場(chǎng)景下饮焦,如一個(gè)第三方類要注入到 Spring 容器,但是該類沒有提供 set 方法窍侧,那么此時(shí)你就只能使用構(gòu)造方法注入了县踢。
英文水平有限,大概翻譯了下伟件。小伙伴們重點(diǎn)看加粗部分硼啤,也就是說在 Spring3.0 時(shí)代,官方還是提倡 set 方法注入的斧账。
不過從 Spring4.x 開始谴返,官方就不推薦這種注入方式了,轉(zhuǎn)而推薦構(gòu)造器注入咧织。
我們來看看 Spring4.x 的文檔怎么說(https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#beans-setter-injection):
這段內(nèi)容我就不一一翻譯了嗓袱,大家重點(diǎn)看第二段第一句:
The Spring team generally advocates constructor injection
這句話就是說 Spring 團(tuán)隊(duì)倡導(dǎo)通過構(gòu)造方法完成注入。才一個(gè)大版本更新习绢,Spring 咋就變了呢渠抹?別急,人家也給出用構(gòu)造方法注入的理由,第二段翻譯一下大概是這個(gè)意思:
通過構(gòu)造方法注入的方式逼肯,能夠保證注入的組件不可變耸黑,并且能夠確保需要的依賴不為空。此外篮幢,構(gòu)造方法注入的依賴總是能夠在返回客戶端(組件)代碼的時(shí)候保證完全初始化的狀態(tài)大刊。
上面這段話主要說了三件事:
- 依賴不可變:這個(gè)好理解,通過構(gòu)造方法注入依賴三椿,在對(duì)象創(chuàng)建的時(shí)候就要注入依賴缺菌,一旦對(duì)象創(chuàng)建成功,以后就只能使用注入的依賴而無法修改了搜锰,這就是依賴不可變(通過 set 方法注入將來還能通過 set 方法修改)伴郁。
- 依賴不為空:通過構(gòu)造方法注入的時(shí)候,會(huì)自動(dòng)檢查注入的對(duì)象是否為空蛋叼,如果為空焊傅,則注入失敳裎摇趋观;如果不為空,才會(huì)注入成功巷查。
- 完全初始化:由于獲取到了依賴對(duì)象(這個(gè)依賴對(duì)象是初始化之后的)歌馍,并且調(diào)用了要初始化組件的構(gòu)造方法握巢,因此最終拿到的就是完全初始化的對(duì)象了。
在 Spring3.0 文檔中松却,官方說如果構(gòu)造方法注入的話暴浦,屬性太多可能會(huì)讓代碼變得非常臃腫,那么在 4.0 文檔中晓锻,官方對(duì)這個(gè)說法也做了一些訂正:如果用構(gòu)造方法注入的時(shí)候歌焦,參數(shù)過多以至于代碼過于臃腫,那么此時(shí)你需要考慮這個(gè)類的設(shè)計(jì)是否合理砚哆,這個(gè)類是否參雜了太多的其他無關(guān)功能同规,這個(gè)類是否做到了單一職責(zé)。
好吧窟社,你說的總是有理券勺!
這是構(gòu)造方法注入和 set 方法注入的問題,那么上面我們還提到不推薦屬性注入灿里,這又是咋回事呢关炼?
屬性注入其實(shí)有一個(gè)顯而易見的缺點(diǎn),那就是對(duì)于 IOC 容器以外的環(huán)境匣吊,除了使用反射來提供它需要的依賴之外儒拂,無法復(fù)用該實(shí)現(xiàn)類寸潦。因?yàn)樵擃悰]有提供該屬性的 set 方法或者相應(yīng)的構(gòu)造方法來完成該屬性的初始化。換言之社痛,要是使用屬性注入见转,那么你這個(gè)類就只能在 IOC 容器中使用,要是想自己 new 一下這個(gè)類的對(duì)象蒜哀,那么相關(guān)的依賴無法完成注入斩箫。
以上分析都是根據(jù) Spring 官方文檔得來,日常開發(fā)應(yīng)該還是屬性注入較多撵儿,這個(gè)咱們不必糾結(jié)乘客,代碼該咋寫還咋寫,Spring 官方的態(tài)度了解一下即可淀歇,當(dāng)然易核,如果項(xiàng)目允許,也不妨試試 Spring 推薦的代碼規(guī)范浪默。
3. 小結(jié)
好啦牡直,今天就和小伙伴們隨便扯扯 Spring 中的注入方式,希望對(duì)你有幫助~
————————————————
版權(quán)聲明:本文為CSDN博主「kuan_sun」的原創(chuàng)文章纳决,遵循CC 4.0 BY-SA版權(quán)協(xié)議井氢,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/kuan_sun/article/details/122597107