SpringBoot啟動 源碼深度解析(四)

SpringBoot 版本 : 2.2.1.RELEASE
Spring 版本 : 5.2.1.RELEASE
入口類: SpringApplication;SpringApplicationBuilder
說明 : 由于SpringBoot建立在Spring之上,所以分析SpringBoot的啟動過程其實(shí)與Spring是交錯進(jìn)行的,分析的時候會順帶將一些Spring的擴(kuò)展點(diǎn)也提到
注:本文主要講解一些比較重要的關(guān)鍵步驟,不能面面俱到,若有疑問,隨時保持溝通

SpringBoot啟動 源碼深度解析(一)
SpringBoot啟動 源碼深度解析(二)
SpringBoot啟動 源碼深度解析(三)

  • 調(diào)用org.springframework.context.support.AbstractApplicationContext# registerBeanPostProcessors(beanFactory) 方法來注冊攔截bean創(chuàng)建的處理器。接著調(diào)用org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext) 委托方法去注冊BeanPostProcessor實(shí)例
    1. 首先獲取所有BeanPostProcessor類型的beanDefinetion,創(chuàng)建一個BeanPostProcessorChecker后置處理器,此后置處理器用來打印BeanPostProcessor處理器創(chuàng)建用的。
    2. 也將后置處理器分為幾類:實(shí)現(xiàn)優(yōu)先級PriorityOrdered 的、Ordered的、普通的。依次調(diào)用 getBean方法將獲取的bean實(shí)例添加到bean工廠中,重要的是最后需要重新注冊內(nèi)部的后置處理器(實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor接口的)
    3. 最后重新注冊ApplicationListenerDetector處理器,用來偵察內(nèi)部的ApplicationListener監(jiān)聽器。

  • 調(diào)用 org.springframework.context.support.AbstractApplicationContext# initMessageSource() 初始化上下文中的信息資源 .

  • 初始化上下文事件廣播器ApplicationEventMulticaster從bean工廠中若加工不出來對應(yīng)的bean實(shí)例,就是bean定義中沒有,那么會重新創(chuàng)建一個SimpleApplicationEventMulticaster實(shí)例).

  • 接著調(diào)用 org.springframework.context.support.AbstractApplicationContext#onRefresh() 模板方法,此處會回調(diào)ServletWebServerApplicationContextonRefresh方法

    image.png

    1. 兩步操作,首先調(diào)用父類的onRefresh方法,去初始化 this.themeSource = UiApplicationContextUtils.initThemeSource(this);
    2. 然后 調(diào)用createWebServer(),此處就是創(chuàng)建Tomcat服務(wù)器
    image.png

  • 調(diào)用 org.springframework.context.support.AbstractApplicationContext# registerListeners() 方法注冊監(jiān)聽器對象。首先把boot配置的監(jiān)聽器先注冊到上下文事件廣播器中;然后再獲取ApplicationListener類型的bean定義(部分監(jiān)聽器還沒實(shí)例化)添加到org.springframework.context.event.AbstractApplicationEventMulticaster.ListenerRetriever#applicationListenerBeans屬性中;最后發(fā)布早批注冊的監(jiān)聽事件通知監(jiān)聽器。

  • 調(diào)用 finishBeanFactoryInitialization 方法實(shí)例化非延遲加載的單例bean對象,即初始化bean工廠。其中會判定是否有屬性解析器,沒有會從environment中獲取并添加到bean工廠中。設(shè)置臨時類加載器會空,設(shè)置bean定義配置凍結(jié)標(biāo)志為true,將beanDefinitionNames放入到凍結(jié)數(shù)組frozenBeanDefinitionNames中。最后實(shí)例化所有的非延遲化單例對象。

    image.png

    1. ????進(jìn)入到方法????org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons中,使用局部變量保存之前定義的bean名稱,然后遍歷所有的對象,依次判斷。

    1. ????首先獲取bean定義,若不是抽象類并且是單例對象并且不需要延遲初始化的bean名稱,緊接著判斷是否是工廠bean,若不是工廠bean,則直接調(diào)用getBean(benaName)方法實(shí)例化bean定義;若是工廠bean,則需要先在bean名稱前面加上 & 符號再調(diào)用getBean(benaName)方法,再判斷獲取的bean實(shí)例是否是 FactoryBean類型,若是并且沒有設(shè)置安全security檢查,獲取是否需要急切初始化的布爾值賦給變量eagerInit,若為true,則也需要調(diào)用getBean的方法。即如果是工廠bean則需要判斷需要急切初始化參數(shù)值,若為true則表示工廠bean也需要初始化,否則不需要調(diào)用getBean方法 :
      2.1. getBean() -> doGetBean() -> 進(jìn)入方法。首先獲取轉(zhuǎn)換之后的bean名稱(不包含或者去除factoryBean的前綴 & 之后的名稱),調(diào)用 getSingleton(beanName)方法檢查當(dāng)前名稱是否是早期注冊的單例實(shí)例,先從singletonObjects(一級緩存) 緩存Map中獲取,若沒有并且單例實(shí)例正在創(chuàng)建中,則從 earlySingletonObjects(二級緩存)中獲取單例實(shí)例,若以然為空,但是允許早期引用為true,則從 singletonFactory 單例工廠(三級緩存)中獲取實(shí)例, 然后將獲取的單例實(shí)例放入到 earlySingletonObjects二級緩存)中,并且從單例工廠中(三級緩存)移除。 ??即:singletonObjects 中若沒有并且單例正在初始化 -> earlySingletonObjects 若沒有并且允許早期暴漏引用 -> singletonFactories 若沒有,則返回空,若有對應(yīng)的工廠去處理,則獲取工廠的getObject()對象,放入到 earlySingletonObjects ,同時從 singletonFactories 中移除當(dāng)前bean名稱。 ??
      2.2. 若獲取的實(shí)例不為空,調(diào)用
      org.springframework.beans.factory.support.AbstractBeanFactory#
      getObjectForBeanInstance() 獲取當(dāng)前bean實(shí)例。如果當(dāng)前bean名稱間接引用了工廠(名稱以&)但不是 FactoryBean類型,則拋BeanIsNotAFactoryException異常。即 禁止&開頭的非FactoryBean類型的bean。
      2.3. 若當(dāng)前bean不是工廠bean 或者名稱以&開頭,則直接返回實(shí)例;否則說明是工廠bean,則先從緩存 factoryBeanObjectCache 中獲取bean實(shí)例,若緩存中不存在,將當(dāng)前對象實(shí)例轉(zhuǎn)換成FactoryBean類型,然后調(diào)用 org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean 從 FactoryBean中獲取bean實(shí)例。
      2.4. 進(jìn)到方法,若工廠是單例并且bean名稱在單例bean定義(一級緩存)中則首先嘗試從 factoryBeanObjectCache 緩存Map中獲取對應(yīng)的實(shí)例。若沒有,調(diào)用 org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean,進(jìn)入到方法發(fā)現(xiàn)調(diào)用的是 object = factory.getObject()獲取的對象。所以:工廠bean 獲取實(shí)例時調(diào)用對應(yīng)的getObject方法返回的實(shí)例。再次檢查 factoryBeanObjectCache緩存中是否有對應(yīng)的實(shí)例(此處再次檢查是因?yàn)榭赡艽嬖谘h(huán)引用處理出發(fā)了自定義getBean()的調(diào)用)。若緩存中有,直接賦值給要返回的對象 object;若沒有則判斷是否應(yīng)該執(zhí)行后處理,org.springframework.beans.factory.support.FactoryBeanRegistrySupport#postProcessObjectFromFactoryBean(),然后進(jìn)入到 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization()方法,執(zhí)行bean初始化之后的后處理操作。獲取所有的BeanPostProcessor調(diào)用其 postProcessAfterInitialization(Object bean, String beanName)方法,??此處可以實(shí)現(xiàn)對初始化的bean實(shí)例進(jìn)行修改??。
      2.5. 若調(diào)用 Object sharedInstance = getSingleton(beanName) 返回的bean實(shí)例為空,校驗(yàn)若是prototype類型,則拋異常; 檢查parentBeanFactory工廠中是否存在bean定義,若父工廠不為空,并且子工廠中不包含bean定義,則從父工廠中搜索bean實(shí)例。然后調(diào)用 String[] dependsOn = mbd.getDependsOn(); 獲取bean定義所依賴的所有bean名稱,確保當(dāng)前bean依賴的bean已經(jīng)初始化(即初始化時先初始化依賴的bean).
      2.6. 然后調(diào)用 getBean(dep)先行初始化依賴的bean的實(shí)例,重復(fù)上述步驟,重新獲取bean實(shí)例等等。。。
      2.7. 接著判斷當(dāng)前實(shí)例若是單例模式,首先調(diào)用org.springframework.beans.factory.support.AbstractBeanFactory#createBean方法 -> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean 方法,進(jìn)入方法中,首先調(diào)用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation 此處會先① 執(zhí)行實(shí)例化前得操作,org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance方法創(chuàng)建實(shí)例包裝對象,然后調(diào)用 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#② applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName) 允許后置處理器修改被合并得bean定義,bean定義處理之后設(shè)置為true。然后判斷bean定義如果是單例對象并且允許循環(huán)引用,執(zhí)行代碼addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));解決循環(huán)引用,
      image.png
      首先執(zhí)行g(shù)etEarlyBeanReference方法,允許暴漏早期引用,方法里面首先獲取所有得BeanPostProcessor,判斷若是 SmartInstantiationAwareBeanPostProcessor類型,則回調(diào)后置處理器得子類實(shí)現(xiàn)方法org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(Object bean, String beanName)。
      如果單例對象緩存中不存在bean名稱得話,將bean名稱跟早期暴漏對象工廠添加到單例工廠 singletonFactories(三級緩存)與 已經(jīng)注冊得單例緩存registeredSingletons 中,同時移除earlySingletonObjects (二級緩存)
      2.8. 然后調(diào)用 populateBean(beanName, mbd, instanceWrapper);填充Bean屬性,首先判斷實(shí)例化后置處理器標(biāo)志 hasInstantiationAwareBeanPostProcessors 若為true,則循環(huán)回調(diào) InstantiationAwareBeanPostProcessor實(shí)例得 ③ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)方法,
      執(zhí)行實(shí)例化后處理
      。若方法返回為false,則結(jié)束屬性填充。
      2.9. 接著判斷屬性注入類型若是根據(jù)名稱注入 AUTOWIRE_BY_NAME,則調(diào)用 autowireByName(beanName, mbd, bw, newPvs)填充屬性;若是根據(jù)類型注入 AUTOWIRE_BY_TYPE,則調(diào)用 autowireByType(beanName, mbd, bw, newPvs) 方法完成注入:
      image.png

      2.10. 進(jìn)入方法 autowireByName,首先獲取所有屬性名稱,然后循環(huán)判斷屬性,若在bean定義中并且是工廠bean則返回true,然后執(zhí)行g(shù)etBean得操作,然后調(diào)用 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#registerDependentBean(String beanName, String dependentBeanName) 方法執(zhí)行依賴bean得注冊;若bean定義中沒有或者不是工廠bean,則返回false,不做處理。同理調(diào)用 autowireByType 方法。
      2.11. 接著循環(huán)遍歷已經(jīng)注冊得BeanPostProcessors后置處理器,若是 InstantiationAwareBeanPostProcessor 類型,則首先調(diào)用后置處理器得 postProcessProperties方法,此處會處理內(nèi)置得用來處理
      @Autowired
      得后置處理器 AutowiredAnnotationBeanPostProcessor 和 用來處理@PostConstruct@PreDestroy 得后置處理器CommonAnnotationBeanPostProcessor。
      2.12. 進(jìn)入 AutowiredAnnotationBeanPostProcessor 得回調(diào)方法 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties(PropertyValues pvs, Object bean, String beanName)中,首先調(diào)用方法 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata找到自動注入得元數(shù)據(jù);然后調(diào)用org.springframework.beans.factory.annotation.InjectionMetadata#inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs),然后判斷isField若為true,則反射調(diào)用Field得set方法為成員設(shè)置值,否則反射調(diào)用Method得invoke方法為方法設(shè)置值;最后若屬性值不為空,則調(diào)用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs),此方法會將屬性值轉(zhuǎn)化后填充到BeanWrapper中。
      2.13. 然后調(diào)用 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)方法對以下三種bean實(shí)例進(jìn)行回調(diào)(BeanNameAwareBeanClassLoaderAware、BeanFactoryAware),然后再調(diào)用BeanPostProcessor得初始化前方法 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)對bean進(jìn)行初始化前回調(diào),④ 允許初始化前修改;緊接著調(diào)用初始化方法:優(yōu)先調(diào)用 InitializingBean類型得afterPropertiesSet初始化方法,再調(diào)用initMethod方法,最后調(diào)用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#⑤ applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)對bean進(jìn)行初始化后處理。

    總結(jié)doCreateBean()得邏輯:createInstance 創(chuàng)建bean實(shí)例-> populateBean 填充bean屬性-> initializeBean 回調(diào)bean調(diào)用aware得set回調(diào)方法、調(diào)用后置處理器得初始化前得回調(diào)方法 postProcessBeforeInitialization()、調(diào)用 InitializingBean得afterPropertiesSet()初始化回調(diào)方法、調(diào)用 initMethod()回調(diào)方法、最后調(diào)用 后置處理器得 postProcessAfterInitialization()回調(diào)方法)

    1. ????最后遍歷所有的bean定義,調(diào)用 getSingleton(beanName) 獲取單例實(shí)例,判斷當(dāng)前單例實(shí)例若是 SmartInitializingSingleton 類型,則需要會調(diào)afterSingletonsInstantiated()方法,否則不做處理。
  • 最后調(diào)用 org.springframework.context.support.AbstractApplicationContext#finishRefresh()方法完成刷新,首先調(diào)用子類得實(shí)現(xiàn)方法org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#finishRefresh子類首先調(diào)用父類得finishRefresh之后執(zhí)行:

    • 清理緩存
    • 初始化聲明周期 LifecycleProcessor處理器,設(shè)置啟動狀態(tài)為running
    • 發(fā)布上下文刷新事件

    然后再調(diào)用org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#startWebServer開啟Tomcat服務(wù),成功開啟之后發(fā)布一個 ServletWebServerInitializedEvent事件。

  • 最后如果啟動出現(xiàn)異常,銷毀單例bean,清空所有相關(guān)得緩存,取消刷新(設(shè)置激活狀態(tài)為false),將異常拋給調(diào)用者;若啟動成功,清空相關(guān)得緩存。

  1. ? 文章要是勘誤或者知識點(diǎn)說的不正確,歡迎評論,畢竟這也是作者通過閱讀源碼獲得的知識,難免會有疏忽!
  2. ? 要是感覺文章對你有所幫助,不妨點(diǎn)個關(guān)注,或者移駕看一下作者的其他文集,也都是干活多多哦,文章也在全力更新中。
  3. ? 著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容