顛覆面試官的Spring自動注入

Spring系列 - 你可能學了假的Spring

轉(zhuǎn)載自: ---->>> 原文連接

在提到spring的自動注入,我們肯定都了解,網(wǎng)絡上有大幅篇章的博客都有去描述spring的各種依賴注入的方式,以及說明.但是本文的自動注入可能會顛覆你對spring的認知(在debuger源碼時,我也被顛覆了.可以說百度上的很多博客對于spring的自動注入都理解錯了,下文將會通過我的理論+代碼+源碼證明理論的方式說明!)

自動注入需要相對于手動裝配來說. 在spring應用程序當中假設你的A類依賴了B類. 需要在A類當中提供一個B類的屬性, 再加上setter, 繼而在xml當中配置、描述一下這兩個類之間的依賴關系. 如果做完當容器初始化過程中會實例化A瞒窒,在實例化A的過程中會填充屬性谦絮,由于在xml中已經(jīng)配置已旧、描述好兩者的關系肪获,故而spring會把B給A裝配上馍悟;這種由程序員自己配置柠衍、描述好依賴關系的寫法叫做手動裝配. 看個例子吧!

手動裝配

setter注入

image
application.xml

創(chuàng)建兩個類,在xml里配置這兩個類,并且TestService依賴于DemoService,在Demo.java內(nèi)getBean()并調(diào)用xxx()方法打印demoService驗證是否注入成功.

關于依賴注入的資料可以參考官網(wǎng)

這一章節(jié)提到了一個非常重要的知識點洋满,也是一個常見的spring面試題目。spring有幾種依賴注入方式珍坊?那么這個問題應該怎么回答呢牺勾?
[圖片上傳失敗...(image-247d0f-1578620950928)]
主要是最后面這句話:

DI exists in two major variants: Constructor-based dependency injection and Setter-based dependency injection.

DI存在兩個主要變體:基于構造函數(shù)的依賴注入和基于Setter的依賴注入。

不管是手動裝配還是自動裝配都是基于這兩種方式或者變體方式來的阵漏;但是這里一定要回答到主要和變體兩個名詞驻民,因為有的注入方式就不是這兩種翻具,而是這兩種其中一種的變體方式;比如在一個類的屬性上面加@Autowired回还,這種方式注入屬性的方式就是利用了java的反射知識,@Autowired這種注入的方式是setter注入方式的一種變體

但是這里需要說明的是所謂的setter其實和屬性無關裆泳,什么意思呢?一般的setter方法會對應一個屬性柠硕,但是spring的基于setter的注入方式是不需要屬性的工禾,僅僅只需要一個setter方法,下面這個例子來說明這個問題.

TestService.java
application.xml

運行上面的代碼可以看到spring也會調(diào)用這個setWwwww方法蝗柔,如果仔細觀察調(diào)用椢趴可以看到這個方法是在spring容器初始化的時候?qū)嵗?code>TestService,完成TestService的注入功能時候調(diào)用過來的

可能有人會說如果使用注解呢癣丧?比如如下代碼,不過TestService同樣會注入DemoService,但不過是通過field.set去完成注入的槽畔,不是通過setter,再次說明一下這是setter的一種變體(官方支持的注入方式只有兩種胁编!一種是通過setter注入厢钧,一種是通過構造方法`注入)

image

Constructor注入

image
application.xml

自動裝配

前言

我看過很多資料說@Autowired也算自動裝配,其實在一個屬性上面加@Autowired注解應該屬于手動裝配嬉橙,我會通過大量源碼和例子來證明的這個理論早直。spring官網(wǎng)有說明自動裝配有四種模型分別是nobyType憎夷、byName莽鸿、constructor. 參考官網(wǎng)資料,而現(xiàn)在流行著這么一種說法:@Autowired就是通過byType來完成注入的拾给。其實嚴格意義上來講這句話大錯特錯祥得,因為byType在spring官網(wǎng)來說僅僅是一種自動注入模型而已,每種模型都有自己的代碼技術實現(xiàn)蒋得,而@Autowired是一個注解级及,這個注解會被spring的后置處理器(AutowiredAnnotationBeanPostProcessor)解析,和處理byType不是同一回事额衙。如果需要講清楚他們的區(qū)別和證明@Autowired不是自動裝配則首先要搞明白什么是自動裝配饮焦。我接下來會花一定篇幅來解釋自動裝配的知識,然后回過頭來講他們的區(qū)別和證明@Autowired屬性是手動裝配窍侧。

那么接下來討論自動注入或者叫自動裝配县踢;自動注入的出現(xiàn)是因為手動裝配過于麻煩,比如某個類X當中依賴了10個其他類那么配置文件將會變的特別冗余和臃腫伟件,spring的做法是可以為這個X類提供一種叫做自動裝配的模型硼啤,無需程序員去手動配置X類的依賴關系。有人會疑問斧账,用注解不也是可以解決這個xml臃腫的問題谴返?確實用注解可以解決煞肾,但是我們現(xiàn)在討論的是自動裝配的問題,就不能用注解嗓袱;為什么不能用注解來討論自動裝配的問題呢籍救?因為在不配置BeanFactoryPostProcessor(后置處理器)和修改BeanDefinition的情況下注解的類是不支持自動裝配的(關于BeanFactoryPostProcessorBeanDefinition的知識以后有時間更新).這也是證明@Autowired默認不是自動裝配的一個證據(jù),那又如何證明注解類是默認不支持自動裝配呢渠抹?下文我會解釋一個注解類默認是不支持自動裝配的蝙昙。也就是說如果討論自動裝配最好是用xml形式來配置spring容器才會有意義..

image
image
image

上面代碼運行起來,TestService能注入DemoService逼肯,但是在xml配置文件中并沒有去手動維護耸黑、描述他們之間的依賴關系桃煎,而是在xml的根標簽上面寫了一行default-autowire=“byType”,注意byType是一種注入模式篮幢。 因為在官網(wǎng)文檔里面spring也是這么定義的,自動注入模式和前面提到的依賴注入方式(setter和構造方法)是兩回事为迈,簡單說:依賴注入是一個過程三椿,主要通過setter和構造方法以及一些變體的方式完成把對象依賴、或者填充上的這個過程叫做依賴注入葫辐,不管手動裝配還是自動裝配都有這個過程搜锰;而自動裝配模式是一種完成自動裝配依賴的手段體現(xiàn),每一種模型都使用了不同的技術去查找和填充bean耿战;而從spring官網(wǎng)上面可以看到spring只提出了4中自動裝配模式,(第一種是no蛋叼,表示不使用自動裝配.)。這四個模式分別用一個整形來表示剂陡,存在spring的beanDefinition當中狈涮,任何一個類默認是no這個裝配模式,也就是一個被注解的類默認的裝配模型是no也就是手動裝配鸭栖;下圖我會展示spring源碼當中如何定義每個類型對應的int值多少歌馍,需要注意的是官網(wǎng)上面說的四種注入模型其中并沒有我們熟悉的@Autowired,這也再一次說明@Autowired不是自動裝配晕鹊;可能有人會提出假設我在TestService類的某個屬性上面加上@Autowired之后這個TestService類就會不會成了自動裝配呢松却?@Autowired是不是會改變這個類A當中的autowireMode呢?我們z可以寫一個例子來證明一下:

在此之前可以先看一下Spring源碼中定義的4種裝配模型

image

自定義一個spring后置處理器
image

image

控制臺輸出
image

可以看到結果為0溅话,說明這個類不是自動裝配晓锻,其實這已經(jīng)能證明@Autowried不是自動裝配了,但是還有更直接的證據(jù)證明他不是自動裝配飞几,就是通過spring源碼當中處理@Autowried的代碼可以看出砚哆,下文在上源碼證明!

使用byType & byName注入

xml配置了TestServer.java與DemoService.java都是自動裝配模型為byType講道理autowireMode=2

控制臺打印結果

如果把注入模型改成byName則結果應該會改變

(寫這個破玩意好累啊循狰。窟社。券勺。。等心情好了再更新源碼的吧灿里。关炼。。)

簡單提一嘴子吧...

調(diào)試spring源碼當中的org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean方法匣吊,這個方法主要就是完成屬性填充的儒拂,也就是大家說的注入


總結

不管咋樣,寫了那么多總結一下吧...

byType是一種自動注入模型色鸳;@Autowried是一個注解社痛,兩個沒有關系,一點關系都沒有命雀;@Autowried講道理算是手動裝配蒜哀;那么一個注解的類到底能不能開啟自動裝配呢?答案是可以的吏砂,

  1. 還有撵儿,Spring的注入方式只有兩種!
    • setter注入,
    • 構造方法注入狐血,
  2. 注入模式有4種淀歇,上面提到過的
    • no、
    • byType匈织、
    • byName浪默、
    • constructor

其他的一些注入方式都只不過是這兩種方式內(nèi)其中一種的變體!

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缀匕,一起剝皮案震驚了整個濱河市纳决,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弦追,老刑警劉巖岳链,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異劲件,居然都是意外死亡掸哑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進店門零远,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苗分,“玉大人,你說我怎么就攤上這事牵辣∷ぱⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長择浊。 經(jīng)常有香客問我戴卜,道長,這世上最難降的妖魔是什么琢岩? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任投剥,我火速辦了婚禮,結果婚禮上担孔,老公的妹妹穿的比我還像新娘江锨。我一直安慰自己,他們只是感情好糕篇,可當我...
    茶點故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布啄育。 她就那樣靜靜地躺著,像睡著了一般拌消。 火紅的嫁衣襯著肌膚如雪挑豌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天拼坎,我揣著相機與錄音浮毯,去河邊找鬼。 笑死泰鸡,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的壳鹤。 我是一名探鬼主播盛龄,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼芳誓!你這毒婦竟也來了余舶?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤锹淌,失蹤者是張志新(化名)和其女友劉穎匿值,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赂摆,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡挟憔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了烟号。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绊谭。...
    茶點故事閱讀 40,567評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖汪拥,靈堂內(nèi)的尸體忽然破棺而出达传,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布宪赶,位于F島的核電站宗弯,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏搂妻。R本人自食惡果不足惜罕伯,卻給世界環(huán)境...
    茶點故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望叽讳。 院中可真熱鬧追他,春花似錦、人聲如沸岛蚤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涤妒。三九已至单雾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間她紫,已是汗流浹背硅堆。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贿讹,地道東北人渐逃。 一個月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像民褂,于是被迫代替她去往敵國和親茄菊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,585評論 2 359