1. 程式人生 > >spring 是如何注入物件的和bean 建立過程分析

spring 是如何注入物件的和bean 建立過程分析

文章目錄:

  1. beanFactory 及 bean 生命週期起步
  2. BeanFactory refresh 全過程
  3. BeanFactoryPostProcessor 和 BeanPostProcessor 解析
  4. 使用 BeanPostProcessor 實現 aop 和 springboot Cache 相關注解實現
  5. 【本文】spring 是如何注入物件的

首先需要知道一個大致實現

  • 這個注入過程肯定是在 BeanPostProcessor 中實現的

  • spring 是在 beanFactory.getBean 進行 bean 例項化的,即懶載入

  • 根據第二條,也就是說在 getBean 的時候才會去呼叫所有 BeanPostProcessor

  • 第二篇文章說到,BeanFactory 的 refresh 過程只是註冊 BeanPostProcessor,真正執行在 getBean 方法中

  • MergedBeanDefinitionPostProcessor 也是一種 BeanPostProcessor 它重新弄了個一個生命週期函式,替代了 BeanPostProcessor 預設的生命週期函式,這麼看吧,我貼一小段原始碼

    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof MergedBeanDefinitionPostProcessor) {
            MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
            bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
        }
    }

    它允許你在非 BeanFactoryProcess 中去修改 Bean 定義

  • InstantiationAwareBeanPostProcessor 也是一種 BeanPostProcessor 它也重新定義了一個生命週期函式,它允許把屬性值注入到屬性物件中

@Autowired 載入定義的過程

我們先不看 bean 的建立過程,就看 MergedBeanDefinitionPostProcessor 的實現子類,這裡看名字猜測 AutowiredAnnotationBeanPostProcessor 應該就是幹這件事的,所以我們接下來可以直接看 AutowiredAnnotationBeanPostProcessor 的 postProcessMergedBeanDefinition 方法的程式碼。

順著方法的呼叫,可以知道在 buildAutowiringMetadata 是真正查詢這些註解的地方,最後 checkConfigMembersMember 註冊進了 bean 定義,具體如何查詢的讀者自行檢視原始碼。

這裡只是將 Member 註冊進了 bean 定義,真正例項化在填充 Bean 的過程中,下面說到 bean 的建立過程可以知道是何時注入的。

Bean 的建立過程

前面說到 spring 是在 getBean 的過程中進行 Bean 建立的,建立 bean 分為幾個步驟

  1. 獲取 bean 定義
  2. new Bean()
  3. 執行生命週期函式 (前)
  4. 建立依賴項
  5. 填充 bean
  6. 執行生命週期函式(後)

入口為 BeanFactory.getBean ,BeanFactory 的實現類為 DefaultListableBeanFactory 這些你可以在 BeanFactory 的 refresh 過程中找到

根據原始碼,如果 bean 還不存在時,就會執行 bean 的建立流程

獲取 bean 定義在這段原始碼中

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

緊跟著,根據 Bean 定義搜尋其依賴項,並建立 bean ,可以看出是遞迴建立 bean

String[] dependsOn = mbd.getDependsOn();
for (String dep : dependsOn) {
    getBean(dep);
}

然後就建立 bean 了

if (mbd.isSingleton()) {
    createBean(beanName, mbd, args);
}

// 真正的執行在 doCreateBean 過程中
Object beanInstance = doCreateBean(beanName, mbdToUse, args);

建立 bean 第一步 new Bean

if (instanceWrapper == null) {
    instanceWrapper = createBeanInstance(beanName, mbd, args);
}

建立 bean 第二步,執行所有的 processor ,包含 MergedBeanDefinitionPostProcessor ,所以在這一步註冊注入選項

applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

建立 bean 第三步,填充 bean ,這裡做的 @Autowired 注入

populateBean(beanName, mbd, instanceWrapper);

最終的處理過程在 AutowiredAnnotationBeanPostProcessor 的 postProcessPropertyValues 函式中

metadata.inject(bean, beanName, pvs);

因為在前面已經獲取過依賴項,並且把其丟進了容器,所以這裡是直接用反射寫進去就可以了

建立 bean 第四步,初始化 bean ,這裡有一個方法注入,方法注入原來發生在初始化 bean 過程中,還有就是生命週期函式執行了,包含 BeanPostProcessor 的前置後置生命週期,初始化方法等

小說明 :AutowiredAnnotationBeanPostProcessor 即是 一個 MergedBeanDefinitionPostProcessor 也是一個 InstantiationAwareBeanPostProcessor

一點小推廣

創作不易,希望可以支援下我的開源軟體,及我的小工具,歡迎來 gitee 點星,fork ,提 bug 。

Excel 通用匯入匯出,支援 Excel 公式
部落格地址:https://blog.csdn.net/sanri1993/article/details/100601578
gitee:https://gitee.com/sanri/sanri-excel-poi

使用模板程式碼 ,從資料庫生成程式碼 ,及一些專案中經常可以用到的小工具
部落格地址:https://blog.csdn.net/sanri1993/article/details/98664034
gitee:https://gitee.com/sanri/sanri-tools-ma