1. 程式人生 > >品Spring:對@Autowired和@Value註解的處理方法

品Spring:對@Autowired和@Value註解的處理方法

在Spring中能夠完成依賴注入的註解有JavaSE提供的@Resource註解,就是上一篇文章介紹的。

還有JavaEE提供的@javax.inject.Inject註解,這個用的很少,因為一般都不會去引用JavaEE的jar包。

程式設計新說注:JavaEE早已經被Oracle拋棄了。JavaEE這個名字已經成為歷史。

還有兩個就是@Value和@Autowired註解,這可是Spring自己的親孩子。所以這兩個使用的最多。

雖然註解不一樣,但是目的一樣,都是用來進行依賴注入,而且Spring處理依賴注入都是用的一個套路。

在上一篇文章中已經說的很詳細了,這裡再說一遍,就當鞏固了。

從最通俗的角度來說,依賴注入就是這樣的:


首先,要知道誰需要被注入。用A表示。

其次,要知道把誰注入。用B表示。

再者,從容器中找到它。用find(B)表示。

最後,完成注入動作。用<-表示。

因此,整個過程可以用一個式子表示:

A <- find(B)

Spring採用的統一方案如下:

1)找出一個類中需要被注入的元素,其實就是欄位和方法,然後使用InjectedElement和InjectionMetadata來表示。

2)找出需要注入什麼型別的物件,其實就是欄位型別和方法引數型別,然後使用DependencyDescriptor來表示。

3)根據第2步的描述,從容器中找到(解析出)這個物件,這由容器負責,beanFactory.resolveDependency(..)。

4)完成具體注入動作,就是把第3步的值應用到第1步裡,是欄位的話就是設定一下,是方法的話就呼叫一下。

這是依賴主人的巨集觀過程,但是對不同的註解,有些細節性的東西是不同的。下面一起來看下。


被注入元素


如果被注入的是一個欄位,如下圖01:


表示欄位的值是否必須被注入,還有快取欄位的值。

如果被注入的是一個方法,如下圖02:


表示方法的引數值是否必須被注入,還有快取方法的引數值。

程式設計新說注:這裡快取的欄位值和方法引數值,並不是一個具體的值,只是一個依賴描述(DependencyDescriptor)。稍後會看到。


依賴的描述


Spring對@Autowired的處理是按型別進行的,所以必須按型別過濾容器中的所有bean,這樣效率會低一些。


所以當過濾到這樣的bean之後,就會快取下bean的名稱,下次就直接用這個bean名稱去找,就會很快了。

這就涉及到對依賴描述的擴充套件,如下圖03:


這裡把bean的名稱和型別都記錄下來,下次直接進行短路操作,使用getBean(..),不用再遍歷了。


從容器中解析出依賴


對欄位來說,如下圖04:


使用Field生成一個依賴描述,然後去容器中解析出能夠和欄位型別相容的所有bean,並把bean名稱放入autowiredBeanNames這個Set中去。

然後進行快取,如下圖05:


主要快取了bean名稱,在下次再裝配時,進行短路操作。

對於方法來說,如下圖06:


由於方法有多個引數,每個引數都需要依賴,所以就按引數逐個處理。

使用Method和引數索引生成一個MethodParameter,然後再用它生成依賴描述。

然後去容器中解析出能夠和該方法引數型別相容的所有bean,並把bean名稱放入autowiredBeans這個Set中去。

然後再進行快取,如下圖07:



依賴的注入


對於欄位,呼叫set方法,如下圖08:


對於方法,呼叫invoke方法,如下圖09:


以上就是具體的處理過程和對通用處理的擴充套件。

這裡面似乎有一個問題,就是對@Autowired的處理和@Value的處理應該是不太相同的,但是上述過程中並沒有體現。

這一部分其實是交給了容器去處理了,在beanFactory.resolveDependency(..)這個解析依賴的方法裡進行了處理。


對構造方法的處理


構造方法是很特殊的,在容器準備例項化一個bean時,就會去找出一個最合適的構造方法,然後通過反射呼叫它來生成一個物件。

如果一個類定義了多個構造方法,Spring會通過一個複雜方式從中選出一個最合適的。

由於@Autowired註解可以作用於構造方法上,所以可以用它來適當改變Spring的這種選擇方式。

把@Autowired註解標到其中幾個構造方法上,這樣Spring只會在這些標註解的之間進行選擇,相當於起一個收窄作用。

此時還會把預設無參的構造方法也作為備選,因為標註解的都不能滿足的話,就只能使用預設的。

如果一個類有多個構造方法,但我們想非常明確的使用某一個,那就把@Autowired標在它上,並把註解的required屬性設定為true。

這樣只會把這一個選出來,此時不會再考慮預設無參的構造方法。相當於起一個特指作用。

程式設計新說注:這個特指作用的用法和上面那個收窄作用的用法不能混合使用,只能二選一,否則報錯。

這就是@Autowired註解對構造方法的作用。


和bean後處理器的結合


構造方法的處理邏輯是在determineCandidateConstructors這個方法裡呼叫的,目的是給我們一個決定構造方法的機會,如果決定不出來也不要緊,Spring還會自己決定。

剩下的就和之前的一樣了,在postProcessMergedBeanDefinition方法裡準備好和依賴注入相關的元資料。

在postProcessProperties方法裡,根據元資料從容器中解析出依賴並完成注入動作。

>>> 品Spring系列文章 <<<

 

品Spring:帝國的基石

品Spring:bean定義上梁山

品Spring:實現bean定義時採用的“先進生產力”

品Spring:註解終於“成功上位”

品Spring:能工巧匠們對註解的“加持”

品Spring:SpringBoot和Spring到底有沒有本質的不同?

品Spring:負責bean定義註冊的兩個“排頭兵”

品Spring:SpringBoot輕鬆取勝bean定義註冊的“第一階段”

品Spring:SpringBoot發起bean定義註冊的“二次攻堅戰”

品Spring:註解之王@Configuration和它的一眾“小弟們”

品Spring:bean工廠後處理器的呼叫規則

品Spring:詳細解說bean後處理器

品Spring:對@PostConstruct和@PreDestroy註解的處理方法

品Spring:對@Resource註解的處理方法

 

>>> 熱門文章集錦 <<<

 

畢業10年,我有話說

【面試】我是如何面試別人List相關知識的,深度有點長文

我是如何在畢業不久只用1年就升為開發組長的

爸爸又給Spring MVC生了個弟弟叫Spring WebFlux

【面試】我是如何在面試別人Spring事務時“套路”對方的

【面試】Spring事務面試考點吐血整理(建議珍藏)

【面試】我是如何在面試別人Redis相關知識時“軟懟”他的

【面試】吃透了這些Redis知識點,面試官一定覺得你很NB(乾貨 | 建議珍藏)

【面試】如果你這樣回答“什麼是執行緒安全”,面試官都會對你刮目相看(建議珍藏)

【面試】迄今為止把同步/非同步/阻塞/非阻塞/BIO/NIO/AIO講的這麼清楚的好文章(快快珍藏)

【面試】一篇文章幫你徹底搞清楚“I/O多路複用”和“非同步I/O”的前世今生(深度好文,建議珍藏)

【面試】如果把執行緒當作一個人來對待,所有問題都瞬間明白了

Java多執行緒通關———基礎知識挑戰

品Spring:帝國的基石

 

作者是工作超過10年的碼農,現在任架構師。喜歡研究技術,崇尚簡單快樂。追求以通俗易懂的語言解說技術,希望所有的讀者都能看懂並記住。下面是公眾號和知識星球的二維碼,歡迎關注!

 

       

&n