1. 程式人生 > >spring原始碼分析系列5:ApplicationContext的初始化與Bean生命週期

spring原始碼分析系列5:ApplicationContext的初始化與Bean生命週期

回顧Bean與BeanDefinition的關係. BeanFactory容器. ApplicationContext上下文.

首先總結下:

  1. 開發人員定義Bean資訊:分為XML形式定義;註解式定義
  2. ApplicationContext蒐集Bean的定義;儲存到BeabFactory容器的中。
  3. BeanFactory根據這些BeanDefinition建立Bean.快取起來供我們使用。

[開發人員]--標註-->[Bean定義] ---蒐集 -->[BeanDefinition]---建立-->[Bean]

此節:我們從程式碼層面分析此過程.

refresh()

refresh()方法描述了ApplicationContext的初始化過程,這個過程大部分工作都是執行Bean定義到BeanDefinition到Bean的過程。

refresh()大致可以分為五部分來看:

1.BeanDefinition入庫前準備階段:

  • prepareRefresh();:主要工作環境屬性的初始化,校驗。
  • obtainFreshBeanFactory();: 準備一個beanFactory()(注:XML配置形式的Bean大多在此時執行了蒐集入庫)
  • prepareBeanFactory(beanFactory);:配置beanFactory的相關資訊,包括類載入;類載入器,解析器,需要的依賴和需要忽略的依賴,早期的Bean級別後處理器,建立環境相關Bean
  • postProcessBeanFactory(beanFactory); 該方法只要是針對web型別的上下文中的增加配置beanFactory的相關屬性。

總的的來說,此階段是在做beanFactory的相關配置。

2.BeanDefinition蒐集入庫階段:

  • invokeBeanFactoryPostProcessors(beanFactory):此方法主要了蒐集註解型BeanDefinition,註冊這些BeanDefinition, 執行BeanFactoryPostProcessor.postProcessBeanFactory()方法,做入庫時的修改操作。

此過程非常的精妙。由PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()全全負責,
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法上本質就幹了兩件事:

  1. 執行註冊型BeanFactoryPostProcessor:此時有個重要的ConfigurationClassPostProcessor註冊器,此類會將註解配置型的BeanDefinition找到,並註冊到BeanFactory中。
  2. 執行普通型別的BeanFactoryPostProcessor:做入庫的修改操作。

3.部分特殊功能的Bean提前建立:
此階段把少部分特殊用處的BeanDefinition先建立Bean供使用。

  • registerBeanPostProcessors(beanFactory);例項化一些BeanPostProcessor為將來的BeanDefinition生成Bean時做準備。。
  • initMessageSource(); 初始化ApplicationContext的國際化相關元件Bean,訊息繫結,訊息解析
  • initApplicationEventMulticaster();:初始化廣播器元件Bean,用於初始化過程中廣播階段性事件。
  • onRefresh(); 初始化子類中特殊Beans(也算是一個擴充套件點)
  • registerListeners();:將容器中的監聽器Bean,設定到廣播器中去。

4.普通BeanDefinition生成Bean階段
此階段是大部分BeanDefinition生成Bean的階段。

  • finishBeanFactoryInitialization(beanFactory);:
    此過程,就是上篇文章說的 ,applicationContext上下文觸發beanFactory內部的BeanDefinition建立Bean。

    我們想象一個場景: 先往一個機器內先放入原料BeanDefinition後,然後再按下開關開始製造.ApplicationContext在此處就好比按下開關.開始Bean的製造,Bean的製作過程是一條流水線,流水線上有不同型別的機器對原料做不同的處理,最終得到Bean

ApplicationContext呼叫DefaultListableBeanFactory.preInstantiateSingletons()開始觸發Bean的建立:

doGetBean:

  1. 首先檢查倉庫中是否已經建立過此Bean,有取出來
  2. 沒有就準備走流水線建立Bean建立.
  3. 建立前先檢查物料有沒有?有,標記當前Bean在建立中
  4. 檢查是否有依賴,有的話,先去載入建立依賴Bean. 又回到了1
  5. 判斷作用域,上createBean()流水線準備執行。

doGetBean->createBean:

  1. 載入Bean的Class類
  2. 驗證以及準備需要覆蓋的方法

doGetBean->createBean->代理物件: 返回代理物件

  1. 建立代理物件:給BeanPostProcessors 一個機會來返回代理物件來代替真正的例項(此處返回的是針對自定義TargetSource的Bean)

doGetBean->createBean->doCreateBean:沒有建立自定義代理物件繼續執行

  1. 使用合適的例項化策略來建立Bean(工廠方法、建構函式自動注入、簡單初始化),並得到Bean包裝類BeanWrapper物件。
  2. 呼叫BeanDefinitionPostProcessor後置處理器,修改 BeanDefinition
  3. 解決單例模式的迴圈依賴:解決辦法是儘早暴露Bean的引用到快取中,讓其他物件可以能引用到他
  4. populateBean設定bean的屬性
  5. initializeBean:

doGetBean->createBean->doCreateBean->initializeBean 例項化Bean

  1. invokeAwareMethods:執行_awre型別的方法
  2. applyBeanPostProcessorsBeforeInitialization執行BeanPostProcessor的前置方法
  3. invokeInitMethods: 執行InitializingBean介面的afterPropertiesSet ,invokeCustomInitMethod執行自定義的init-method方法
  4. applyBeanPostProcessorsAfterInitialization:執行BeanPostProcessor的後置方法
  5. 返回Bean. 至此BeanDefinition到Bean的生產過程完成。

5.applicationContext的收尾階段

  • finishRefresh();
    收尾階段其實也算是applicationContext的擴充套件點。Lifecycle介面生命週期介面,

    (1.首先會從Bean容器中獲取LifecycleProcessor型別的Bean,如果沒有則建立一個預設的DefaultLifecycleProcessor。LifecycleProcessor是幹嘛用的?LifecycleProcessor是用來處理Lifecycle介面的bean的。

    (2.使用獲得LifecycleProcessor執行實現了Lifecycle介面的Bean的start()方法

    (3.釋出上下文初始化完成事件

    (4.Participate in LiveBeansView MBean, if active.不是很清楚幹嘛的。

Bean的生命週期

看完了refresh()方法。我們再來總結下Bean的生命週期。

用一張圖表示

Bean的完整生命週期分為四個階段:

  1. 第一階段:例項化階段。
    從Bean定義的收集到BeanDefinition的入庫順序執行
    BeanDefinitionRegistryPostProcessor註冊處理器,註冊一些BeanDefinition
    BeanFactoryPostProcessor,對入庫的BeanDefinition進行定義的修改。
    BeanWrapper的產生,BeanWrapper是Bean的早期產品。
    populateBean()執行屬性的設定
    總結:此階段是BeanDefinition->BeanWrapper ,各種屬性的設定

  2. 第二階段:初始化階段:主要是執行各種初始化方法
    invokeAwareMethods(beanName, bean);執行Aware屬性的相關設定。
    BeanPostProcessor.postProcessBeforeInitialization前置方法的執行,
    如果實現了InitializingBean.afterPropertiesSet()則執行此方法
    執行自定義的initMethod方法。
    BeanPostProcessor.postProcessBeforeInitialization後置方法的執行,

  3. 第三階段:使用階段
    getBean從容器的快取中取出Bean

  4. 第四階段:銷燬階段
    執行DisposableBean.distroy方法
    執行自定義detry-method

總結:

整個spring初始化過程可以看做是

  • 物料(BeanDefinition)的蒐集入庫(BeanFactory)
  • 生產線(getBean())取出物料建立成品(Bean)
  • 成品(Bean)入庫(BeanFactory)

歡迎大家關注我的公眾號【原始碼行動】,最新個人理解及時奉送。

相關推薦

spring原始碼分析系列5:ApplicationContext初始Bean生命週期

回顧Bean與BeanDefinition的關係. BeanFactory容器. ApplicationContext上下文. 首先總結下: 開發人員定義Bean資訊:分為XML形式定義;註解式定義 ApplicationContext蒐集Bean的定義;儲存到BeabFactory容器的中。 BeanFa

spring原始碼分析】IOC容器初始(二)

前言:在【spring原始碼分析】IOC容器初始化(一)中已經分析了匯入bean階段,本篇接著分析bean解析階段。 1.解析bean程式呼叫鏈 同樣,先給出解析bean的程式呼叫鏈: 根據程式呼叫鏈,整理出在解析bean過程中主要涉及的類和相關方法。 2.解析bean原始碼分

Spring原始碼分析系列ApplicationContext 相關介面架構分析

在使用Spring的時候,我們經常需要先得到一個ApplicationContext物件,然後從該物件中獲取我們配置的Bean物件

spring原始碼分析系列4:ApplicationContext研究

ApplicationContext介面 首先看一下一個最基本的上下文應該是什麼樣子 ApplicationContext介面的註釋裡寫的很清楚: 一個基本applicationContext應該提供: 訪問Bean的能力 提供載入資源的能力 釋出事件的能力 解析訊息、支援國際化的能力 Abstrac

spring原始碼學習(5.1.0版本)——Bean初始(中)

目錄   前言 createBean 有自定義TargetSource代理類的生成 resolveBeforeInstantiation applyBeanPostProcessorsBeforeInstantiation postProcessBeforeIn

spring原始碼學習(5.1.0版本)——Bean初始(上)

目錄   前言 源頭 preInstantiateSingletons方法 getBean(String beanName) doGetBean getObjectForBeanInstance getObjectFromFactoryBean doGe

精盡Spring MVC原始碼分析 - WebApplicationContext 容器的初始

> 該系列文件是本人在學習 Spring MVC 的原始碼過程中總結下來的,可能對讀者不太友好,請結合我的原始碼註釋 [Spring MVC 原始碼分析 GitHub 地址](https://github.com/liu844869663/spring-framework) 進行閱讀 > > Spring

NSQ原始碼分析(一)——nsqd的初始及啟動流程

nsq原始碼地址:https://github.com/nsqio/nsq 版本1.1.0  NSQ原始碼分析系列是我通過閱讀nsq的原始碼及結合網上的相關文章整理而成,由於在網上沒有找到很詳細和完整的文章,故自己親自整理了一份。如果有錯誤的地方,還請指正,希望這系列的文章給您帶來

【kubernetes/k8s原始碼分析】kubelet原始碼分析之容器網路初始原始碼分析

一. 網路基礎   1.1 網路名稱空間的操作 建立網路名稱空間: ip netns add 名稱空間內執行命令: ip netns exec 進入名稱空間: ip netns exec bash   1.2 bridge-nf-c

dubbo原始碼分析-消費端啟動初始過程-筆記

消費端的程式碼解析是從下面這段程式碼開始的 <dubbo:reference id="xxxService" interface="xxx.xxx.Service"/> ReferenceBean(afterPropertiesSet) ->getObject() ->ge

Android wpa_supplicant原始碼分析--啟動之全域性初始

1. wpa_supplicant簡介 wpa_supplicant是用來用來支援無線中各種加密方式的,包括WEP、WPA/WPA2和WAPI(中國特有)、EAP(8021x)。wpa_s通過socket與上層(framework)和底層(driver)通訊,向上接收命令和傳

《深入理解SPARK:核心思想原始碼分析》——SparkContext的初始(仲篇)——SparkUI、環境變數及排程

《深入理解Spark:核心思想與原始碼分析》一書第一章的內容請看連結《第1章 環境準備》 《深入理解Spark:核心思想與原始碼分析》一書第二章的內容請看連結《第2章 SPARK設計理念與基本架構》 由於本書的第3章內容較多,所以打算分別開闢四篇隨筆分別展現。 本文展現第3章第二部分的內容:

《深入理解Spark:核心思想原始碼分析》——SparkContext的初始(伯篇)——執行環境元資料清理器

《深入理解Spark:核心思想與原始碼分析》一書第一章的內容請看連結《第1章 環境準備》 《深入理解Spark:核心思想與原始碼分析》一書第二章的內容請看連結《第2章 SPARK設計理念與基本架構》 由於本書的第3章內容較多,所以打算分別開闢四篇隨筆分別展現。本文展現第3章第一部分的內容: 第3章

spring原始碼分析系列 (2) spring拓展介面BeanPostProcessor

主要分析內容: 一、BeanPostProcessor簡述與demo示例 二、BeanPostProcessor原始碼分析:註冊時機和觸發點   一、BeanPostProcessor簡述與demo示例 BeanPostProcessor是spring非常重要的拓展介面,例如aop通過拓展

ABP原始碼分析五:ABP初始全過程

ABP在初始化階段做了哪些操作,前面的四篇文章大致描述了一下。 為個更清楚的描述其脈絡,做了張流程圖以輔助說明。其中每一步都涉及很多細節,難以在一張圖中全部表現出來。每一步的細節(會涉及到較多介面,類,呼叫關係,步驟流程什麼的)會在後面的文章中通過其他圖和文字詳細描述。其實如果仔細分析Abp原始碼的話,會發現

suricata 3.1 原始碼分析13 (流初始

簡介 Suricata中用於管理和維護流的模組稱為Flow Engine,主要由兩部分實現,第一部分的入口點是FlowHandlePacket函式,用於為新資料包進行流查詢/分配,另一部分是FlowManagerThread執行緒,用於對超時的流進行刪除。

RPC框架(六)dubbo原始碼分析--dubbo服務提供者初始

一、概述 dubbo服務提供者由dubbo:service來定義,從前面可以看到,Spring把dubbo:service解析成一個ServiceBean,ServiceBean實現了ApplicationListener和InitializingB

Lighttpd1.4.20原始碼分析 筆記 fdevent系統-初始

C程式在進行真正的編譯之前都要進行預編譯。 我們看看fdevent系統中的一些巨集: #if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H) # if defined HAVE_STD

jquery原始碼分析之jQuery物件初始

在jquery實際應用中可通過$或jQuery生成jquery物件,如$("#hr_three")可生成jquery物件,jquery是如何做到的呢?jquery載入時,入口為如下匿名方法,(function( global, factory ) {...} ([color=

rocketmq之原始碼分析broker入口BrokerController初始過程(十六)

接著上一章的BrokerController的基礎功能講,本章主要介紹的是BrokerController的初始化操作,在初始化的