隨筆- 59  評論- 822  文章- 0 

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

 

       

 

posted on 2019-10-09 15:04  編程新說(李新杰)  閱讀(...)  評論(... 編輯 收藏

七乐彩2011年走势图南方双彩