spring源碼之bean的初始化及循環引用

實例化方法,把bean實例化,並且包裝成BeanWrapper

1、點進這個方法裏面。

 

 

 

這個方法是反射調用類中的 factoryMethod 方法。 這要知道@Bean 方法的原理, 實際上
spring 會掃描有@bean 註解的方法, 然後把方法名稱設置到 BeanDefinition factoryMethod
屬性中, 接下來就會調到上面截圖中的方法實現@Bean 方法的調用。 
2、 有參構造函數的時候

determineConstructorsFromBeanPostProcessors
這個方法是 BeanPostProcessor 接口類的首次應用, 最終會掉到
AutowiredAnnotationBeanPostProcessor 類的方法, 在方法中會掃描有註解的構造函數然後完
成裝配過程。 然後把有有@Autowired 註解的構造函數返回。

3、 無參構造函數的實例化

 

 

 這就是簡單的反射實例化。 大部分類的實例化都會走這個邏輯
4、 類中註解的收集
實例化完成後接下來就需要對類中的屬性進行依賴注入操作, 但是類裏面屬性和方法的依
賴注入往往用@Autowired 或者@Resource 註解, 那麼這些註解的依賴注入是如何完成的
呢?
註解的收集:

 

 

 也是通過 BeanPostProcessor 接口類型實例來挨個處理的。
A、 首先是
CommonAnnotationBeanPostProcessor 類, 這個類完成了@Resource 註解的屬性或
者方法的收集
這個類還對@PostConstruct @PreDestory 支持

 

 

 

 

 

 收集過程
1、 看緩存裏面有沒有 InjectionMetadata 對象
2、 從類中獲取所有 Field 對象, 循環 field 對象, 判斷 field 有沒有@Resource 註解,
如果有註解封裝成 ResourceElement 對象
3、 從類中獲取所有 Method 對象, 循環 Method 對象, 判斷 Method 有沒有@Resource
註解, 如果有註解封裝成 ResourceElement 對象
4、 最終把兩個 field Method 封裝的對象集合封裝到 InjectionMetadata 對象中

B、 然後是
AutowiredAnnotationBeanPostProcessor 類, 對@Autowired 註解的屬性和方法
的收集。 收集過程基本上跟@Resource 註解的收集差不多, 這裏就不贅述了

 

5IOC\DI
對應的方法:

 

 

 這裏又是一個 BeanPostProcessor 類型接口的運用, 前面我們講到了@Resource@Autowired 註解的收集, 那麼這個方法就是根據收集到的註解進行反射調用。 

 

 

 

 

 循環收集到的 metaData 中的 list 對象, 然後挨個調用裏面的 InjectedElement inject 方法完成依賴注入。 

 

 

 

 

 其中 value 值的獲取, 如果依賴的屬性是一個引用類型必定會觸發該屬性的
BeanFactory.getBean 操作, 從而從 spring 容器中獲取到對應的實例。 方法的依賴注
入類似這裏就不再贅述。

6bean 實例化後的操作
代碼走到這裏:

 

 

 A、 首先是對某些 Aware 接口的調用

 

 

B、 然後@PostConstruct 註解方法的調用

 

 

 這裏又是一個 BeanPostProcessor 接口的運用,
前面講過, 有@PostConstruct 註解的方法會收集到一個 met
就是通過 BeanPostProcessor 接口調到
CommonAnnotationBeanPostProcessor 類, 然後在類中拿
根據對象裏面的容器來反射調用有註解的方法。 代碼如下:

 

 

 @PostConstruct 註解的容器會收集到 initMethods 容器中, 接下來就是方法的

反射調用。

 

 

 

CInitializingBean 接口和 init-method 屬性調用

 

 

 Init-method 屬性調用是在 afterPropertiesSet 之後

 

 

 afterPropertiesSetInit-method和有@PostConstruct註解的方法其實核
心功能都是一樣的, 只是調用時序不一樣而已, 都是在該類實例化和 IOC 做完後調用
的, 我們可以在這些方法中做一些在 spring 或者 servlet 容器啓動的時候的初始化
工作。 比如緩存預熱, 比如緩存數據加載到內存, 比如配置解析, 等等初始化工作。
在這個方法裏面還有一個重要的邏輯

 

 

 

也是一個 BeanPostProcessor 接口的運用, 在這裏會返回 bean 的代理實例, 這個
就是 AOP 的入口。
DFactoryBean 接口
帶入如下:

 

 

 

 在實例化和 IOC/DI 做完後, 就會調用 FactoryBean 類型的接口, 如果要獲取到
FactoryBean 類本身, 就必須加上”&”符號, 比如
beanFactory.getBean(&beanName)


 

 

  BeanFactory.getBean(beanName” )只能獲取到 getObject()方法返回的實
例。
getObject 方法返回的實例會有單獨的緩存存儲, 跟其他實例不是同一個緩存, 對應的緩
存是: factoryBeanObjectCache 

E、 循環依賴
循環依賴請參照流程圖理解
https://www.processon.com/view/link/5df9ce52e4b0c4255ea1a84f
循環依賴只會出現在單例實例無參構造函數實例化情況下
有參構造函數的加@Autowired 的方式循環依賴是直接報錯的, 多例的循環依賴也是
直接報錯的

 

 

 

 

 循環依賴步驟:
1A 類無參構造函數實例化後, 設置三級緩存
2A populateBean 進行依賴注入, 這裏觸發了 B 類屬性的 getBean 操作
3B 類無參構造函數實例化後, 設置三級緩存
4B populateBean 進行依賴注入, 這裏觸發了 A 類屬性的 getBean 操作
5A 類之前正在實例化, singletonsCurrentlyInCreation 集合中有已經
有這個 A 類了, 三級緩存裏面也有了, 所以這時候是從三級緩存中拿到的提前暴露的
A 實例, 該實例還沒有進行 B 類屬性的依賴注入的, B 類屬性爲空。
6B 類拿到了 A 的提前暴露實例注入到 A 類屬性中了
7B 類實例化已經完成, B 類的實例化是由 A 類實例化中 B 屬性的依賴注入觸發
getBean 操作進行的, 現在 B 已經實例化, 所以 A 類中 B 屬性就可以完成依賴注
入了, 這時候 A B 屬性已經有值了
8B A 屬性指向的就是 A 類實例堆空間, 所以這時候 B A 屬性也會有值了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章