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

 

       

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM