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

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

@Resource是Java的註解,表示一個資源,它具有雙向的含義,一個是從外部獲取一個資源,一個是向外部提供一個資源。

這其實就對應於Spring的注入和註冊。當它用在欄位和方法上時,表示前者。當它用在類上時表示後者。Spring只提供了對前者的支援。

該註解本身表示的是資源,資源的含義是很寬泛的。由於絕大部分情況下在使用Spring的時候,它的容器裡都是普通的bean,所以這個註解就作為bean的注入來使用了。

對於依賴注入這個事情,整體可以分為三步:

1)找出需要被注入的元素,即標了註解的欄位或方法

2)根據註解的描述,在容器中找出依賴的bean

3)完成注入,即設定欄位的值或進行方法呼叫

我們可以分析下,這裡面都會遇到哪些難處理的問題:


1)找出標註解的欄位和方法很簡單,使用Java反射即可。難的是如何表示它們,因為它們就是被注入的元素。

2)要在容器中找出依賴的bean,首先要知道依賴什麼樣子的bean,也就是要想辦法把依賴需求給表示出來。

我們遇到的首個問題同樣是如何表示,如何描述?等把它們解決了,才會進入如何去做的環節。

舉一個例子吧,一個老師要將他們班40位同學的成績排名。他遇到的第一個問題也是如何把40個成績表示出來。

假設有三種方式吧:

1)寫到excel表格裡

2)存到資料庫中

3)寫到一張紙上

再來看看這三種方式下,完成排序的手段是:

1)使用excel的排序函式

2)使用sql的order by

3)人肉排序

可見,雖然最後都達到了結果,但是不同的表示方式對應的排序手段卻相差很大,自然有的簡單,有的難。

當然,也可以把40個成績放入一個數組,然後使用類庫中現成的排序工具進行排序。

不得不說,最終又回到了資料結構和演算法上來。一個是表示或描述,一個是手段或方法。

一起來看看Spring是如何描述和如何操作的。

程式設計新說注:還是那句話,實際的處理會比較複雜,我們還是側重從整體流程上把握。


被注入元資料


能夠被注入的元素只有欄位和方法,方法又包括setter方法和普通方法。(構造方法是被單獨處理的,和此處的不混合)

所以Spring使用InjectedElement類,來表示被注入的元素,如下圖01:


對於依賴的型別,自然就是欄位的型別,屬性的型別或普通方法的第一個引數型別(可以看出普通方法只能有一個引數):如下圖02:



依賴的注入,也非常簡單,是欄位的話就set一下,是方法的話就invoke一下,如下圖03:


因此,關鍵是要把具體的值(也就是依賴)從容器中找出來。

以上這只是一個注入元素,一個類中可以有多個注入元素,所以還有一個以類為單位的描述。

所以Spring使用InjectionMetadata類,來表示一個類的注入元資料,如下圖04:


這裡有兩個注入元素的集合,一個是Collection型別,一個是Set型別,原因在上一篇文章中解釋過了。

這兩個類是Spring的通用抽象,用作所有注入元素和注入元資料的父類。

在處理@Resource註解時對InjectedElement類進行了擴充套件,如下圖05:


name表示依賴的bean名稱,isDefaultName表示是否沒有顯式指定名稱,lookupType表示依賴的型別。

接下來該讀取註解@Resource的屬性,為注入元素類的欄位賦值了,如下圖06:


首先獲取到這個註解,然後讀出它的name和type屬性值。如果name為空字串,則表明沒有顯式指定名稱,那就是用預設的名稱。

如果是欄位就用欄位名,如果是普通方法就用方法名,如果是setter方法就用屬性名。

如果type的值是Object.class,則表明沒有顯式指定型別,那就讀取被注入元素的型別。

如果是欄位就用欄位型別,如果是普通方法就用第一個引數的型別,如果是setter方法就用屬性型別。

這樣就獲取到了依賴的名稱和型別。

以上這些資訊都是對被注入元素的描述,下面還有對依賴的描述。


對依賴的描述


首先是注入點,InjectionPoint類,如下圖07:


如果是方法的話,現在就要具體到引數了,如果是欄位的話,則還是欄位。

然後是依賴描述,DependencyDescriptor類,繼承了注入點類,如下圖08:


如方法名,方法的引數以及引數索引,欄位名,是否必須等等。


最後就是對依賴描述的擴充套件,如下圖09:


把上面獲取到的型別作為依賴描述裡的依賴型別。

以上這些就是對依賴的描述,接下來就是按照這個依賴描述來從容器中找出符合的依賴。


獲取依賴的邏輯


下面是依賴的查詢邏輯,如下圖10:


如果使用的是預設名稱,且容器中不包含這個名稱的bean,則按照型別去解析依賴。

否則就是顯式指定了名稱或容器中包含這個名稱的bean,則按照名稱去解析依賴。

當然,如果容器不具有自動裝配功能的話,則按照名稱去容器中獲取一個bean。

程式設計新說注:

在面試時,幾乎所有的人都會說@Resource是按名稱進行依賴注入的,其實是不完全正確的。

這可能是受官方文件的影響,所以大家都是這麼用的,所以總是會顯式指定註解的name屬性。

其實Spring對它的處理也支援按型別查詢依賴的bean。


bean後處理器確定執行時機


最後,照例要和bean後處理器結合起來,是CommonAnnotationBeanPostProcessor這個類。

也是在postProcessMergedBeanDefinition這個方法裡完成注入元資料的獲取與快取,已備後用,如下圖11:


也是在postProcessProperties這個方法裡完成依賴的注入,如下圖12:

 

>>> 品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註解的處理方法

 

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

 

畢業10年,我有話說

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

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

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

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

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

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

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

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

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

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

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

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

品Spring:帝國的基石

 

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

 

       

&n