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注入
創(chuàng)建兩個類,在xml里配置這兩個類,并且
TestService
依賴于DemoService
,在Demo.java內(nèi)getBean()
并調(diào)用xxx()
方法打印demoService
驗證是否注入成功.
這一章節(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方法,下面這個例子來說明這個問題.
運行上面的代碼可以看到spring也會調(diào)用這個
setWwwww
方法蝗柔,如果仔細觀察調(diào)用椢趴可以看到這個方法是在spring容器初始化的時候?qū)嵗?code>TestService,完成TestService
的注入功能時候調(diào)用過來的
可能有人會說如果使用注解呢癣丧?比如如下代碼,不過
TestService
同樣會注入DemoService
,但不過是通過field.set
去完成注入的槽畔,不是通過setter
,再次說明一下這是setter
的一種變體(官方支持的注入方式只有兩種胁编!一種是通過setter注入厢钧,一種是通過
構造方法`注入)
Constructor注入
自動裝配
前言
我看過很多資料說
@Autowired
也算自動裝配,其實在一個屬性上面加@Autowired
注解應該屬于手動裝配嬉橙,我會通過大量源碼和例子來證明的這個理論早直。spring官網(wǎng)有說明自動裝配有四種模型分別是no
、byType
憎夷、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
的情況下注解的類是不支持自動裝配的(關于BeanFactoryPostProcessor
和BeanDefinition
的知識以后有時間更新).這也是證明@Autowired
默認不是自動裝配的一個證據(jù),那又如何證明注解類是默認不支持自動裝配呢渠抹?下文我會解釋一個注解類默認是不支持自動裝配的蝙昙。也就是說如果討論自動裝配最好是用xml形式來配置spring容器才會有意義..
上面代碼運行起來,
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種裝配模型
自定義一個spring后置處理器
控制臺輸出
可以看到結果為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講道理算是手動裝配蒜哀;那么一個注解的類到底能不能開啟自動裝配呢?答案是可以的吏砂,
- 還有撵儿,Spring的注入方式只有兩種!
- setter注入,
- 構造方法注入狐血,
- 注入模式有4種淀歇,上面提到過的
- no、
- byType匈织、
- byName浪默、
- constructor
其他的一些注入方式都只不過是這兩種方式內(nèi)其中一種的變體!