Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))

風中有朵雲做的雨發表於2019-04-15

前言

此篇是補充上篇未分析完的finishBeanFactoryInitialization部分
配合上篇食用效果更佳

Spring啟動過程——原始碼分析

finishBeanFactoryInitialization(beanFactory)

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
主要方法preInstantiateSingletons()
遍歷List beanNames
如果Bean 不是抽象&是單例&不是lazy

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))

如果不是FactoryBean

getBean進入doGetBean 下面四張圖都是
doGetBean.1

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
doGetBean.2
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
doGetBean.3
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
doGetBean.4
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
如果是bean是單例
重點方法 getSingleton
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
大致執行如下

   //先從快取中取 第一次進來時沒有值的
   Object singletonObject = this.singletonObjects.get(beanName);
   //存在 則return
   if(singletonObject!=null) return;
   //解決迴圈依賴
   beforeSingletonCreation(beanName);
   //真正建立bean
   singletonObject = singletonFactory.getObject();
   afterSingletonCreation(beanName);
   //加入快取
   addSingleton(beanName, singletonObject);
   return singleObject
複製程式碼

真正建立Bean是createBean() 如果是bean是多例

    //this.prototypesCurrentlyInCreation.set(beanName)
    beforePrototypeCreation(beanName);  
    prototypeInstance = createBean(beanName, mbd, args);
    //this.prototypesCurrentlyInCreation.remove()
    afterPrototypeCreation(beanName);
複製程式碼

單例多例建立Bean都會呼叫到createBean

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
真正建立Bean是createBean()
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))

//一般用於建立aop代理 
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
//如果上邊沒有代理 這裡會真正開始建立
Object beanInstance = doCreateBean(beanName, mbdToUse, args)
複製程式碼

createBean->resolveBeforeInstantiation

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
doCreateBean.1
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
doCreateBean.2
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
doCreateBean.3
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
走向如下面流程圖 doCreateBean->createBeanInstance
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))

applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName)
bp instanceof MergedBeanDefinitionPostProcessor -> bp.postProcessMergedBeanDefinition(mbd, beanType, beanName)

populateBean

為剛剛例項化好的Bean進行屬性等賦值

  • BeanWrapper為null直接報錯或者return

  • InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
    官方的解釋是:讓使用者可以自定義屬性注入。比如使用者實現一 個 InstantiationAwareBeanPostProcessor 型別的後置處理器,並通過 postProcessAfterInstantiation 方法向 bean 的成員變數注入自定義的資訊。當然,如果無 特殊需求,直接使用配置中的資訊注入即可。另外,Spring 並不建議大家直接實現 InstantiationAwareBeanPostProcessor 介面,如果想實現這種型別的後置處理器,更建議 通過繼承 InstantiationAwareBeanPostProcessorAdapter 抽象類實現自定義後置處理器

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))

  • 這裡會出現一個Spring的內部processor:AutowiredAnnotationBeanPostProcessor
    Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
    執行下去 進入postProcessProperties 首先找出所有的註解包括@Value @Autowired然後進行呼叫inject方法進行賦值
    Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
    最終是通過反射實現最終賦值
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);  
field.set(bean, value);
複製程式碼

applyPropertyValues(beanName, mbd, bw, pvs);
將屬性應用到 bean 物件中

  • 檢測屬性值列表是否已轉換過的,若轉換過,則直接填充屬性,無需再次轉換

  • 遍歷屬性值列表 pvs,解析原始值 originalValue,得到解析值 resolvedValue

  • 對解析後的屬性值 resolvedValue 進行型別轉換

  • 將型別轉換後的屬性值設定到 PropertyValue 物件中,並將 PropertyValue 物件存入 deepCopy 集合中

  • 將 deepCopy 中的屬性資訊注入到 bean 物件中

流程圖

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))

exposedObject = initializeBean(beanName, exposedObject, mbd)

餘下的初始化工作

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
invokeAwareMethods(beanName, bean)
若 bean 實現了 BeanNameAware、BeanFactoryAware、BeanClassLoaderAware 等介面,則向 bean 中注入相關物件
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)
例項化前執行後置處理器對應的postProcessBeforeInitialization方法
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))

invokeInitMethods(beanName, wrappedBean, mbd)

  1. 判斷是否是InitializingBean的實現,執行介面規定的初始化afterPropertiesSet
  2. 執行invokeCustomInitMethod,方法大致是
    找出所有初始化方法(@Bean initMethod屬性指定的方法) mbd.getInitMethodName() 對應去執行
    Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)
執行 bean 初始化後置操作,AOP 會在此處向目標物件中織入切面邏輯
Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))

如果是FactoryBean

FactoryBean一直都沒怎麼用過 所以自己寫了demo用下

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))

    @Autowired
    private Student2 student2;
複製程式碼

debug一下 檢視下執行過程

Spring啟動過程——原始碼分析(finishBeanFactoryInitialization(beanFactory))
發現它是在Student2.Class是在populateBean的時候呼叫processor進行inject時被例項化的,此時發現是FactoryBean就直接被呼叫了getObject 拿到這個bean 也就是說,一開始被例項化的只有MyFactoryBean這個類,而沒有Student2這個類
MyFactoryBean此時beanName=&myFactoryBean

總結

這次Spring ioc原始碼看了我好幾天,收穫還是挺大的,也總結

  1. 檢視原始碼前提:是必須要知道怎麼用
  2. 如果實在看不懂,可以google找再總結
  3. 有時有些很底層的可以先跳過,先直接到知道必將執行的方法打斷點,由後往前看方法棧debug(如FactoryBean這部分)

最後關於Spring總結 主要按著下面四點去看 1)、Spring容器在啟動,先儲存Bean定義資訊

  • xml註冊bean
  • 註解註冊Bean

2)、Spring容器會在XX的情況下建立Bean

  • 用到這個bean的時候 去建立 *finishBeanFactoryInitialization 統一建立bean

3)、後置處理器 *每一個Bean建立完成 會使用處理器處理

  • AutowiredAnnotationBeanPostProcessor 處理自動注入
  • XXXPostProcessor

4)、事件驅動模型 *ApplicationListener 事件監聽 *ApplicationEventMulticaster 事件派發

相關文章