1. 程式人生 > >Spring Core Container 原始碼分析三:Spring Beans 初始化流程分析

Spring Core Container 原始碼分析三:Spring Beans 初始化流程分析

前言

本文是筆者所著的 Spring Core Container 原始碼分析系列之一;

本篇文章主要試圖梳理出 Spring Beans 的初始化主流程和相關核心程式碼邏輯;

本文轉載自本人的部落格,傷神的部落格 http://www.shangyang.me/2017/04/01/spring-core-container-sourcecode-analysis-beans-instantiating-process/

本文為作者的原創作品,轉載需註明出處;

原始碼分析環境搭建

參考 Spring Core Container 原始碼分析二:環境準備

測試用例

依然使用這個官網上的用例,來進行除錯;

Person.java


     
      1
     
     
      2
     
     
      3
     
     
      4
     
     
      5
     
     
      6
     
     
      7
     
     
      8
     
     
      9
     
     
      10
     
     
      11
     
     
      12
     
     
      13
     
     
      14
     
     
      15
     
     
      16
     
     
      17
     
     
      18
     
     
      19
     
     
      20
     
     
      21
     
     
      22
     
     
      23
     
     
      24
     
     
      25
     
     
      26
     
     
      27
     
     
      28
     
     
      29
     
     
      30
     
     
      31
     

     
      package org.shangyang.spring.container;
     
     
     
      /**
     
     
       - 
     
     
       - 
      @author shangyang
     
     
       *
     
     
       */
     
     
      public 
      class Person {
     
      
     
     
       String name;
     
     
     
       Person spouse;
     
      
     
      
      public
String getName()
{ return name; } public void setName(String name) { this.name = name; } public Person getSpouse() { return spouse; } public void setSpouse(Person spouse) { this.spouse = spouse; } }

beans.xml


     
      1
     
     
      2
     
     
      3
     
     
      4
     
     
      5
     
     
      6
     
     
      7
     
     
      8
     
     
      9
     
     
      10
     
     
      11
     
     
      12
     
     
      13
     
     
      14
     
     
      15
     
     
      16
     

     
      <beans xmlns="http://www.springframework.org/schema/beans"
     
      
      xmlns:xsi=
      "http://www.w3.org/2001/XMLSchema-instance"
     
      
      xmlns:p=
      "http://www.springframework.org/schema/p"
     
      
      xsi:schemaLocation=
      "http://www.springframework.org/schema/beans
     
     
       http://www.springframework.org/schema/beans/spring-beans.xsd">
     
      
     
      
      <!-- 傳統的方式 -->
     
      
      <bean name="john" class="org.shangyang.spring.container.Person">
     
      
      <property name="name" value="John Doe"/>
     
      
      <property name="spouse" ref="jane"/>
     
      
      </bean>
     
      
     
      
      <bean name="jane" class="org.shangyang.spring.container.Person">
     
      
      <property name="name" value="Jane Doe"/>
     
      
      </bean> 
     
     
      </beans>
     


     
      1
     
     
      2
     
     
      3
     
     
      4
     
     
      5
     
     
      6
     
     
      7
     
     
      8
     
     
      9
     
     
      10
     
     
      11
     
     
      12
     
     
      13
     

     
      @Test
     
     
      public void testApplicationContext(){
     
      
     
      
      @SuppressWarnings(
      "resource")
     
     
       ApplicationContext context = 
      new ClassPathXmlApplicationContext(
      "beans.xml");
     
      
     
     
       Person p = context.getBean(
      "john", Person.class);
     
      
     
     
       assertEquals(
      "John Doe", p.getName() );
     
      
     
     
       assertEquals(
      "Jane Doe", p.getSpouse().getName() );
     
      
     
     
      }
     

原始碼分析

備註,這裡只針對 Spring 容器例項化 singleton bean 的主流程進行介紹;singleton bean 在 Spring 容器中被初始化的特點是,在 Spring 容器的啟動過程中就進行初始化;

(最好的分析原始碼的方式,就是通過高屋建瓴,逐個擊破的方式;首先通過流程圖獲得它的藍圖(頂層設計圖),然後再根據藍圖上的點逐個擊破;最後才能達到融會貫通,胸有成竹的境界;所以,這裡作者用這樣的方式帶你深入剖析 Spring 容器裡面的核心點,以及相關主流程到底是如何運作的。)

主流程

bean-creation-overall-process.pngbean-creation-overall-process.png

本章節我們將詳細去闡述的是,Spring 容器是如何對 Singleton bean 進行初始化並註冊到當前容器的;與之相關的主要有兩個流程,

  1. 解析 bean definitions 並註冊
    解析 bean definitiions 並註冊到當前的 BeanFactory 中;此步驟是在 step 1.1.1.2 obtainFreshBeanFactory 完成;更詳細的介紹參考解析並註冊 bean definitions 流程

  2. 從 #1 中找到所有的已註冊的 singleton bean definitions,遍歷,例項化得到 Singleton beans;此步驟對應的是 step 1.1.1.11 finishBeanFactoryInitialization 開始進行 singleton bean 的構造過程,其後呼叫AbstractBeanFactory#getBean(beanFactory)方法進行構造;更詳細的介紹參考 Do Get Bean 流程。

解析並註冊 bean definitions 流程

該部分參考新的博文 Spring Core Container 原始碼分析七:註冊 Bean Definitions

Do Get Bean 流程

Do Get Bean 流程的入口是 AbstractBeanFactory#doGetBean 方法,主流程圖如下,

do-get-bean-process.png do-get-bean-process.png

主流程大致為,從快取中找到是否已經例項化了該 singleton bean,如果已經例項化好了,那麼就直接返回;如果在快取中沒有找到,則將當前的 bean 封裝為 RootBeanDefinition,然後通過呼叫 DefaultSingletonBeanRegistry#getSingleton 得到初始化好的 singleton bean,然後將其註冊至快取( step 1.3.3 addSingleton ),然後再判斷是普通 bean 還是 factory bean 作必要的處理( step 1.4 getObjectForBeanInstance )後,最後返回;

RootBeanDefinition

初始化了一個 RootBeanDefinition 物件,正如其類名描述的那樣,是該 bean 的頂層描述;包含了 bean 的欄位屬性,ref屬性以及繼