這是史上最全面的Spring的核心流程以及運(yùn)作原理的分析指南
??【Spring核心專(zhuān)題】「IOC容器篇」不看繁瑣的源碼就帶你瀏覽Spring的核心流程以及運(yùn)作原理
??【Spring核心專(zhuān)題】「AOP容器篇」不看繁瑣的源碼就帶你瀏覽Spring的核心流程以及運(yùn)作原理
??【Spring核心專(zhuān)題】「MVC容器篇」不看繁瑣的源碼就帶你瀏覽Spring的核心流程以及運(yùn)作原理
學(xué)好Spring技術(shù)的背景
針對(duì)于每一個(gè)Java的愛(ài)好者而言,無(wú)論是從事面向于微服務(wù)架構(gòu)技術(shù)的領(lǐng)域(SpringCloud、SpringCloud-Alibaba等),還是面向于傳統(tǒng)互聯(lián)網(wǎng)行業(yè)(SpringBoot)以及軟件系統(tǒng)(Spring\SpringBatch)領(lǐng)域,掌握好Spring框架技術(shù)原理和源碼對(duì)排查問(wèn)題以及未來(lái)的面試技術(shù)有著非常重要的幫助和影響,而接下來(lái),筆者會(huì)針對(duì)于Spring的技術(shù)框架的核心源碼流程點(diǎn)進(jìn)行相關(guān)的分析和認(rèn)識(shí),相信閱讀完本篇文章,一定會(huì)對(duì)Spring的源碼和執(zhí)行原理有著很大的幫助和提升。
分析框架核心流程
獲取Spring框架的IOC容器
IOC容器執(zhí)行流程主要核心流程點(diǎn):
- 獲取單例Bean對(duì)象
- 創(chuàng)建單例Bean對(duì)象
- 創(chuàng)建原始Bean對(duì)象
- 解決循環(huán)依賴(lài)
- 填充屬性信息
- 初始化Bean對(duì)象
getBean方法的執(zhí)行流程
- 第一步將beanName或者BeanType類(lèi)型進(jìn)行獲取相關(guān)的容器數(shù)據(jù)對(duì)象,例如:處理以&符號(hào)開(kāi)頭的name名稱(chēng)數(shù)據(jù),以及根據(jù)相關(guān)的alias別名。
- 第二步將存在根據(jù) 名稱(chēng)或者別名進(jìn)行獲取相關(guān)的緩存池找那個(gè)進(jìn)行獲取相關(guān)的對(duì)象實(shí)例
- 如果存在:Spring框架會(huì)調(diào)用getObjectForBeanInstance方法,返回對(duì)應(yīng)的Bean實(shí)例對(duì)象,其中Bean實(shí)例的類(lèi)型有兩種模式:?jiǎn)卫J胶驮湍J?
- 單例模式:緩存中沒(méi)有,創(chuàng)建一個(gè),然后放入緩存中,其中會(huì)對(duì)該單例對(duì)象bean進(jìn)行先關(guān)的攔截和后置工作。
- 原型模式:每次都會(huì)創(chuàng)建新的對(duì)象進(jìn)行返回相關(guān)的對(duì)象。
- 如果當(dāng)前的容器中,無(wú)法獲取到相關(guān)的對(duì)應(yīng)的BeanName的對(duì)象實(shí)例,則會(huì)進(jìn)行想父容器進(jìn)行尋找對(duì)應(yīng)的對(duì)象Bean實(shí)例,如果父容器中存在,直接返回父容器中的數(shù)據(jù)對(duì)象實(shí)例,但是如果父容器還不存在,則會(huì)進(jìn)行創(chuàng)建Bean對(duì)象實(shí)例了,但是在創(chuàng)建之前,會(huì)進(jìn)行解析兩種特殊的Bean操作關(guān)系。
- 如果存在:Spring框架會(huì)調(diào)用getObjectForBeanInstance方法,返回對(duì)應(yīng)的Bean實(shí)例對(duì)象,其中Bean實(shí)例的類(lèi)型有兩種模式:?jiǎn)卫J胶驮湍J?
兩種特殊的Bean實(shí)例的關(guān)聯(lián)關(guān)系
parent bean的繼承關(guān)系,例如,a bean對(duì)象可以在xml文件中繼承相關(guān) a-parent bean的屬性以及相關(guān)的覆蓋操作
處理相關(guān)的depend-ons依賴(lài)關(guān)系操作,這樣子可以根據(jù)依賴(lài)關(guān)系,建立一個(gè)加載和創(chuàng)建Bean之間的前后關(guān)系和依賴(lài)關(guān)系,例如A depend-ons B的bean對(duì)象,那么在創(chuàng)建A之前一定會(huì)先加載和創(chuàng)建B,依此類(lèi)托。
之后進(jìn)行相關(guān)的創(chuàng)建bean的操作控制!
獲取Spring框架的變量容器
singletonObjects:?jiǎn)卫患?jí)緩存池-用于存放完全實(shí)例化+初始化好的對(duì)象Bean,如果從該緩存池中取出的Bean可以直接的使用。
earlySingletonObject:?jiǎn)卫?jí)緩存池-用于存放正在初始化的對(duì)象bean,主要用于解決循環(huán)依賴(lài)的臨時(shí)存放的對(duì)象池。
singletonFactories:用于存放bean對(duì)象的工廠對(duì)象機(jī)制,主要用于創(chuàng)建bean對(duì)象的ObjectFactory。
createBean方法的執(zhí)行流程
- createBean的方法入口,getSIngleton方法:
- 先從singletonObjects集合中獲取相關(guān)的Bean實(shí)例,若不為空,則直接返回。
- 如果獲取不到相關(guān)的對(duì)象實(shí)例在一級(jí)單例緩存池中,則會(huì)進(jìn)行createBeanInstance實(shí)例階段(此部分,接下來(lái)會(huì)詳細(xì)介紹),會(huì)將對(duì)應(yīng)的BeanName添加到singleCurrentlyInCreation集合中,這個(gè)集合主要用于存放相關(guān)的將要?jiǎng)?chuàng)建的對(duì)象bean,這個(gè)是第一步。
- 當(dāng)通過(guò)getObject方法調(diào)用createBean方法的是創(chuàng)建實(shí)例對(duì)象的完成之后,會(huì)將對(duì)象實(shí)例從singleCurrentlyInCreation集合中進(jìn)行轉(zhuǎn)移到singleObjects對(duì)象集合緩存池中,映射關(guān)系為:beanName->singleObject對(duì)象。
createBean的方法要點(diǎn)
解析Bean的類(lèi)型和屬性類(lèi)型特點(diǎn)分析,主要分為以下幾點(diǎn)內(nèi)容:
- 解析相關(guān)的Bean對(duì)象的類(lèi)型。
- 校驗(yàn)和分析處理相關(guān)的override注解修飾的方法,主要用于先去校驗(yàn)和分析是否存在重載方法或者覆蓋方法,方便cglib動(dòng)態(tài)代理的時(shí)候不需要進(jìn)行校驗(yàn),而是直接處理調(diào)用即可。
- 其中有一個(gè)屬性:lookup-method,如果我們希望在單例對(duì)象里面加入一個(gè)原型模式(prototype)的對(duì)象屬性,那么可以考慮使用<lookup-method name="getPrototypeBean", bean = "prototypeBean" /> ApplicationContextAware。
- bean實(shí)例化前的后置處理控制hook鉤子函數(shù)以及相關(guān)回調(diào)機(jī)制控制。
createBean的最核心方法doCreateBean
- 調(diào)用doCreateBean創(chuàng)建bean實(shí)例,此方法算是最底層的創(chuàng)建createBean的代表方法了,首先他會(huì)遵循從緩存中區(qū)獲取相關(guān)的BeanWrapper實(shí)現(xiàn)類(lèi)對(duì)象,并且清除一些臨時(shí)數(shù)據(jù)信息。
- 如果緩存中沒(méi)有相關(guān)的緩存,則會(huì)進(jìn)行手動(dòng)創(chuàng)建bean實(shí)例對(duì)象,將實(shí)例對(duì)象包裹在BeanWrapper實(shí)例類(lèi)對(duì)象并且返回該BeanWrapper對(duì)象。
- 并且采用MergeBeanDefinitionBeanPostProcessor的后置處理器,對(duì)相關(guān)的對(duì)象的abstract和parent的繼承關(guān)系的bean進(jìn)行合并處理。
- 根據(jù)系統(tǒng)的配置是否支持循環(huán)依賴(lài)的選項(xiàng),進(jìn)行選擇和決定是否采用提前暴露bean的早期引用(early reference),主要用于處理的循環(huán)依賴(lài)。
- 之后對(duì)相關(guān)的提前暴露的引用和屬性字段進(jìn)行使用popluateBean方法進(jìn)行引用的屬性進(jìn)行填充,其中也包含了相關(guān)的循環(huán)引用的概念在里面。
- 調(diào)用相關(guān)的initializeBean方法完成余下的初始化工作任務(wù),包含了:initializeBean接口實(shí)現(xiàn)、@PostConstruct注解處理控制、以及init-method方法的屬性處理。
- 注冊(cè)銷(xiāo)毀相關(guān)的distroy-method的屬性以及相關(guān)的preDestory的方法控制。
doCreateBean創(chuàng)建最原始的Bean對(duì)象
主要通過(guò)createBeanInstance方法實(shí)例機(jī)制,其核心流程為:
- 檢測(cè)類(lèi)的訪問(wèn)權(quán)限,若禁止訪問(wèn),則會(huì)拋出異常機(jī)制。
- 如果該對(duì)象bean的factory-method屬性包含了factory工廠方法機(jī)制不為空,則通過(guò)該定義的聲明的相關(guān)的factory方法進(jìn)行創(chuàng)建bean,并且返回結(jié)果。
通過(guò)相關(guān)的構(gòu)造器的方式進(jìn)行構(gòu)建對(duì)象
在此我們會(huì)采用construct的方式進(jìn)行反射進(jìn)行構(gòu)建實(shí)例對(duì)象,并且返回對(duì)象的對(duì)象結(jié)果,步驟如下:
- 創(chuàng)建相關(guān)的BeanWrapperImpl對(duì)象作為先關(guān)的Bean實(shí)例對(duì)象的包裝實(shí)現(xiàn)類(lèi)。
- 之后需要進(jìn)行構(gòu)建相關(guān)的真實(shí)的原始模型對(duì)象,其中上面說(shuō)了,如果該bean定義擁有相關(guān)的factory方法,則會(huì)直接通過(guò)factory方法建立,否則會(huì)采用構(gòu)造器的方式進(jìn)行構(gòu)建哦!
- 會(huì)針對(duì)于該對(duì)象的所有定義以及隱含的構(gòu)造器進(jìn)行分析和處理,采用minOrArg方式計(jì)算出,進(jìn)行分析出了一個(gè)按照參數(shù)數(shù)量進(jìn)行排序的構(gòu)造器列表。(其中會(huì)包含著訪問(wèn)優(yōu)先級(jí)以及參數(shù)個(gè)數(shù)的條件進(jìn)行排序)。
- 一般默認(rèn)而言,會(huì)使用最少參數(shù)的構(gòu)造器,當(dāng)然如果存在默認(rèn)構(gòu)造器,一般會(huì)采用默認(rèn)構(gòu)造器區(qū)進(jìn)行處理,但是如果存在非默認(rèn)的構(gòu)造器,則會(huì)采用參數(shù)注入的方式進(jìn)行構(gòu)造器進(jìn)行構(gòu)建。
-
核心: 我們前面已經(jīng)將構(gòu)造器列表進(jìn)行排序完成后,會(huì)進(jìn)行篩選獲取合適的構(gòu)造器進(jìn)行執(zhí)行構(gòu)建對(duì)象。如果我們獲取到了一個(gè)含有參數(shù)的構(gòu)造器,那么spring框架會(huì)怎么做?
- 先進(jìn)行獲取相關(guān)構(gòu)造器中的所有相關(guān)的形式參數(shù)的名稱(chēng)以及類(lèi)型。
- 在進(jìn)行解析參數(shù),此解析方式會(huì)將對(duì)一些已經(jīng)保存在容器中的數(shù)據(jù)進(jìn)行解析注入以及相關(guān)的類(lèi)型參數(shù)轉(zhuǎn)換機(jī)制。
- 從而計(jì)算構(gòu)造器與數(shù)值類(lèi)型的差異性,選擇最佳何時(shí)的構(gòu)造器方法。
- 當(dāng)我們已經(jīng)篩選出和是的構(gòu)造方法(最終),如果在此使用創(chuàng)建bean對(duì)象實(shí)例的時(shí)候,可以直接使用,無(wú)需在進(jìn)行篩選。
- 之后我們采用初始化策略進(jìn)行構(gòu)建該實(shí)例bean對(duì)象。
- 最后將該對(duì)象注入到我們的BeanWrapperImpl對(duì)象模型中,并返回對(duì)象。
如果通過(guò)構(gòu)造器或者工廠方法都無(wú)法構(gòu)建
那么會(huì)采用組合方式進(jìn)行構(gòu)建該對(duì)象
- 通過(guò)工廠方法進(jìn)行構(gòu)建
- 通過(guò)自定義構(gòu)造器進(jìn)行構(gòu)建
- 通過(guò)默認(rèn)構(gòu)造器進(jìn)行構(gòu)建
構(gòu)建的方式需要配合動(dòng)態(tài)代理機(jī)制
為了方便我們進(jìn)行在對(duì)Springbean容器的對(duì)象進(jìn)行AOP攔截操作處理機(jī)制。

解決循環(huán)依賴(lài)
話(huà)不多說(shuō),就是提前暴露,可以通過(guò)factory避過(guò)去以及@lazy不會(huì)引起錯(cuò)誤等。
IOC容器篇
主要的方法為populateBean方法
popluteBean的方法的執(zhí)行流程
首先會(huì)獲取相關(guān)的注入該類(lèi)對(duì)象bean的屬性列表,我們?cè)偾卸x為pvs。
- 當(dāng)構(gòu)造器構(gòu)建完對(duì)象之后會(huì)進(jìn)行相關(guān)的自定義屬性進(jìn)行填充,但是在進(jìn)行相關(guān)的屬性填充進(jìn)行之前,會(huì)先去嘗試采用系統(tǒng)默認(rèn)后置處理器進(jìn)行填充。
主要通過(guò)參數(shù)名或者參數(shù)類(lèi)型進(jìn)行解析并且填充相關(guān)的依賴(lài)屬性,主要可以通過(guò)的手段就是@Autowired或者@Resource、@Inject等。
之后還會(huì)在采用后置處理器對(duì)屬性進(jìn)行動(dòng)態(tài)pvs的內(nèi)容進(jìn)行填充處理。
-
會(huì)將屬性應(yīng)用到bean中的applyProperyValues方法:
- 在檢測(cè)屬性值是否已經(jīng)完成轉(zhuǎn)換,如果該屬性值已經(jīng)完成轉(zhuǎn)換,則直接使用,無(wú)需再次轉(zhuǎn)換。
- 遍歷屬性列表,解析器屬性的原始值,在通過(guò)PropertisSourcePlaceholdConfigurer進(jìn)行相關(guān)的解析操作,并且完成解析值resolveValue。
最后將的到的解析數(shù)值resolveValue進(jìn)行相關(guān)的類(lèi)型屬性轉(zhuǎn)換操作。
將類(lèi)型轉(zhuǎn)換后的值設(shè)置到PropertyValue對(duì)象中,將PropertyValue對(duì)象存入deepCopy集合中,并且將deepCopy的屬性值注入到bean對(duì)象中。
根據(jù)名稱(chēng)和類(lèi)型進(jìn)行填充
根據(jù)名稱(chēng)注入
就是單純的將bean名稱(chēng)進(jìn)行注入到相關(guān)的非簡(jiǎn)單類(lèi)型的注入機(jī)制。
根據(jù)類(lèi)型注入
- 主要處理@Value注解進(jìn)行注入操作解析機(jī)制!
- 解析數(shù)組、list、map等類(lèi)型的依賴(lài)注入機(jī)制
- 根據(jù)類(lèi)型查找相關(guān)何時(shí)的類(lèi)型數(shù)據(jù)信息
- 如果候選項(xiàng)的數(shù)量為0,則拋出異常。如果=1,則直接從候選列表中進(jìn)行獲取,如果>1,則在多個(gè)候選選項(xiàng)中的獲取最優(yōu)的對(duì)象,否則拋出異常。
- 如果候選選選為class類(lèi)型,則標(biāo)識(shí)候選選選還沒(méi)有完成實(shí)例化,此時(shí)通過(guò)BeanFactory.getBean的方式進(jìn)行實(shí)例化,否則會(huì)直接返回對(duì)象實(shí)例。
初始化Bean對(duì)象
主要是經(jīng)歷了所有的實(shí)例化和處理之后,則會(huì)需要進(jìn)行相關(guān)的初始化方法的調(diào)用,在底層框架表現(xiàn)為initializeBean方法進(jìn)行初始化,執(zhí)行順序的判斷邏輯執(zhí)行流程為:
- 檢測(cè)bean是否實(shí)現(xiàn)了xAware類(lèi)型的接口,如果實(shí)現(xiàn)了,則會(huì)向該bean中注入相關(guān)的x的實(shí)例屬性對(duì)象,主要通過(guò)調(diào)用invokeAwareMethods方法。
- 之后開(kāi)始執(zhí)行初始化的前置操作:例如BeanPostProcessor以及相關(guān)的afterPropertiesSetting方法。
- 執(zhí)行相關(guān)的初始化操作invokeInitMethods方法。
- 執(zhí)行后置的初始化操作,例如BeanPostProcessor的后置處理機(jī)制操作。