【Spring專場】「IOC容器」不看源碼就帶你認識核心流程以及運作原理

這是史上最全面的Spring的核心流程以及運作原理的分析指南

  • 🍃【Spring核心專題】「IOC容器篇」不看繁瑣的源碼就帶你瀏覽Spring的核心流程以及運作原理

  • 🍃【Spring核心專題】「AOP容器篇」不看繁瑣的源碼就帶你瀏覽Spring的核心流程以及運作原理

  • 🍃【Spring核心專題】「MVC容器篇」不看繁瑣的源碼就帶你瀏覽Spring的核心流程以及運作原理

學好Spring技術的背景

針對於每一個Java的愛好者而言,無論是從事面向於微服務架構技術的領域(SpringCloud、SpringCloud-Alibaba等),還是面向於傳統互聯網行業(SpringBoot)以及軟件系統(Spring\SpringBatch)領域,掌握好Spring框架技術原理和源碼對排查問題以及未來的面試技術有着非常重要的幫助和影響,而接下來,筆者會針對於Spring的技術框架的核心源碼流程點進行相關的分析和認識,相信閱讀完本篇文章,一定會對Spring的源碼和執行原理有着很大的幫助和提升。

分析框架核心流程

獲取Spring框架的IOC容器

IOC容器執行流程主要核心流程點:

  • 獲取單例Bean對象
  • 創建單例Bean對象
  • 創建原始Bean對象
  • 解決循環依賴
  • 填充屬性信息
  • 初始化Bean對象
getBean方法的執行流程
  1. 第一步將beanName或者BeanType類型進行獲取相關的容器數據對象,例如:處理以&符號開頭的name名稱數據,以及根據相關的alias別名。
  2. 第二步將存在根據 名稱或者別名進行獲取相關的緩存池找那個進行獲取相關的對象實例
    • 如果存在:Spring框架會調用getObjectForBeanInstance方法,返回對應的Bean實例對象,其中Bean實例的類型有兩種模式:單例模式和原型模式
      • 單例模式:緩存中沒有,創建一個,然後放入緩存中,其中會對該單例對象bean進行先關的攔截和後置工作。
      • 原型模式:每次都會創建新的對象進行返回相關的對象。
    • 如果當前的容器中,無法獲取到相關的對應的BeanName的對象實例,則會進行想父容器進行尋找對應的對象Bean實例,如果父容器中存在,直接返回父容器中的數據對象實例,但是如果父容器還不存在,則會進行創建Bean對象實例了,但是在創建之前,會進行解析兩種特殊的Bean操作關係。
兩種特殊的Bean實例的關聯關係
  • parent bean的繼承關係,例如,a bean對象可以在xml文件中繼承相關 a-parent bean的屬性以及相關的覆蓋操作

  • 處理相關的depend-ons依賴關係操作,這樣子可以根據依賴關係,建立一個加載和創建Bean之間的前後關係和依賴關係,例如A depend-ons B的bean對象,那麼在創建A之前一定會先加載和創建B,依此類託。

之後進行相關的創建bean的操作控制!

獲取Spring框架的變量容器
  • singletonObjects:單例一級緩存池-用於存放完全實例化+初始化好的對象Bean,如果從該緩存池中取出的Bean可以直接的使用。

  • earlySingletonObject:單例二級緩存池-用於存放正在初始化的對象bean,主要用於解決循環依賴的臨時存放的對象池。

  • singletonFactories:用於存放bean對象的工廠對象機制,主要用於創建bean對象的ObjectFactory。

createBean方法的執行流程
  • createBean的方法入口,getSIngleton方法:
    1. 先從singletonObjects集合中獲取相關的Bean實例,若不爲空,則直接返回。
    2. 如果獲取不到相關的對象實例在一級單例緩存池中,則會進行createBeanInstance實例階段(此部分,接下來會詳細介紹),會將對應的BeanName添加到singleCurrentlyInCreation集合中,這個集合主要用於存放相關的將要創建的對象bean,這個是第一步。
    3. 當通過getObject方法調用createBean方法的是創建實例對象的完成之後,會將對象實例從singleCurrentlyInCreation集合中進行轉移到singleObjects對象集合緩存池中,映射關係爲:beanName->singleObject對象。
createBean的方法要點

解析Bean的類型和屬性類型特點分析,主要分爲以下幾點內容:

  1. 解析相關的Bean對象的類型。
  2. 校驗和分析處理相關的override註解修飾的方法,主要用於先去校驗和分析是否存在重載方法或者覆蓋方法,方便cglib動態代理的時候不需要進行校驗,而是直接處理調用即可。
    • 其中有一個屬性:lookup-method,如果我們希望在單例對象裏面加入一個原型模式(prototype)的對象屬性,那麼可以考慮使用<lookup-method name="getPrototypeBean", bean = "prototypeBean" /> ApplicationContextAware。
  3. bean實例化前的後置處理控制hook鉤子函數以及相關回調機制控制。
createBean的最核心方法doCreateBean
  • 調用doCreateBean創建bean實例,此方法算是最底層的創建createBean的代表方法了,首先他會遵循從緩存中區獲取相關的BeanWrapper實現類對象,並且清除一些臨時數據信息。
  • 如果緩存中沒有相關的緩存,則會進行手動創建bean實例對象,將實例對象包裹在BeanWrapper實例類對象並且返回該BeanWrapper對象。
  • 並且採用MergeBeanDefinitionBeanPostProcessor的後置處理器,對相關的對象的abstract和parent的繼承關係的bean進行合併處理。
  • 根據系統的配置是否支持循環依賴的選項,進行選擇和決定是否採用提前暴露bean的早期引用(early reference),主要用於處理的循環依賴。
  • 之後對相關的提前暴露的引用和屬性字段進行使用popluateBean方法進行引用的屬性進行填充,其中也包含了相關的循環引用的概念在裏面。
  • 調用相關的initializeBean方法完成餘下的初始化工作任務,包含了:initializeBean接口實現、@PostConstruct註解處理控制、以及init-method方法的屬性處理。
  • 註冊銷燬相關的distroy-method的屬性以及相關的preDestory的方法控制。
doCreateBean創建最原始的Bean對象

主要通過createBeanInstance方法實例機制,其核心流程爲:

  • 檢測類的訪問權限,若禁止訪問,則會拋出異常機制。
  • 如果該對象bean的factory-method屬性包含了factory工廠方法機制不爲空,則通過該定義的聲明的相關的factory方法進行創建bean,並且返回結果。
通過相關的構造器的方式進行構建對象

在此我們會採用construct的方式進行反射進行構建實例對象,並且返回對象的對象結果,步驟如下:

  1. 創建相關的BeanWrapperImpl對象作爲先關的Bean實例對象的包裝實現類。
  2. 之後需要進行構建相關的真實的原始模型對象,其中上面說了,如果該bean定義擁有相關的factory方法,則會直接通過factory方法建立,否則會採用構造器的方式進行構建哦!
  3. 會針對於該對象的所有定義以及隱含的構造器進行分析和處理,採用minOrArg方式計算出,進行分析出了一個按照參數數量進行排序的構造器列表。(其中會包含着訪問優先級以及參數個數的條件進行排序)。
  4. 一般默認而言,會使用最少參數的構造器,當然如果存在默認構造器,一般會採用默認構造器區進行處理,但是如果存在非默認的構造器,則會採用參數注入的方式進行構造器進行構建。
  5. 核心: 我們前面已經將構造器列表進行排序完成後,會進行篩選獲取合適的構造器進行執行構建對象。如果我們獲取到了一個含有參數的構造器,那麼spring框架會怎麼做?
    • 先進行獲取相關構造器中的所有相關的形式參數的名稱以及類型。
    • 在進行解析參數,此解析方式會將對一些已經保存在容器中的數據進行解析注入以及相關的類型參數轉換機制。
    • 從而計算構造器與數值類型的差異性,選擇最佳何時的構造器方法。
    • 當我們已經篩選出和是的構造方法(最終),如果在此使用創建bean對象實例的時候,可以直接使用,無需在進行篩選。
    • 之後我們採用初始化策略進行構建該實例bean對象。
    • 最後將該對象注入到我們的BeanWrapperImpl對象模型中,並返回對象。
如果通過構造器或者工廠方法都無法構建

那麼會採用組合方式進行構建該對象

  1. 通過工廠方法進行構建
  2. 通過自定義構造器進行構建
  3. 通過默認構造器進行構建

構建的方式需要配合動態代理機制

爲了方便我們進行在對Springbean容器的對象進行AOP攔截操作處理機制。

解決循環依賴

話不多說,就是提前暴露,可以通過factory避過去以及@lazy不會引起錯誤等。

IOC容器篇

主要的方法爲populateBean方法

popluteBean的方法的執行流程

首先會獲取相關的注入該類對象bean的屬性列表,我們再切定義爲pvs。

  1. 當構造器構建完對象之後會進行相關的自定義屬性進行填充,但是在進行相關的屬性填充進行之前,會先去嘗試採用系統默認後置處理器進行填充。

主要通過參數名或者參數類型進行解析並且填充相關的依賴屬性,主要可以通過的手段就是@Autowired或者@Resource、@Inject等。

  1. 之後還會在採用後置處理器對屬性進行動態pvs的內容進行填充處理。

  2. 會將屬性應用到bean中的applyProperyValues方法:

    • 在檢測屬性值是否已經完成轉換,如果該屬性值已經完成轉換,則直接使用,無需再次轉換。
    • 遍歷屬性列表,解析器屬性的原始值,在通過PropertisSourcePlaceholdConfigurer進行相關的解析操作,並且完成解析值resolveValue。
  3. 最後將的到的解析數值resolveValue進行相關的類型屬性轉換操作。

  4. 將類型轉換後的值設置到PropertyValue對象中,將PropertyValue對象存入deepCopy集合中,並且將deepCopy的屬性值注入到bean對象中。

根據名稱和類型進行填充
根據名稱注入

就是單純的將bean名稱進行注入到相關的非簡單類型的注入機制。

根據類型注入
  • 主要處理@Value註解進行注入操作解析機制!
  • 解析數組、list、map等類型的依賴注入機制
  • 根據類型查找相關何時的類型數據信息
  • 如果候選項的數量爲0,則拋出異常。如果=1,則直接從候選列表中進行獲取,如果>1,則在多個候選選項中的獲取最優的對象,否則拋出異常。
  • 如果候選選選爲class類型,則標識候選選選還沒有完成實例化,此時通過BeanFactory.getBean的方式進行實例化,否則會直接返回對象實例。

初始化Bean對象

主要是經歷了所有的實例化和處理之後,則會需要進行相關的初始化方法的調用,在底層框架表現爲initializeBean方法進行初始化,執行順序的判斷邏輯執行流程爲:

  1. 檢測bean是否實現了xAware類型的接口,如果實現了,則會向該bean中注入相關的x的實例屬性對象,主要通過調用invokeAwareMethods方法。
  2. 之後開始執行初始化的前置操作:例如BeanPostProcessor以及相關的afterPropertiesSetting方法。
  3. 執行相關的初始化操作invokeInitMethods方法。
  4. 執行後置的初始化操作,例如BeanPostProcessor的後置處理機制操作。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章