1. 程式人生 > >Spring IOC 源碼簡單分析 01 - BeanFactory

Spring IOC 源碼簡單分析 01 - BeanFactory

ebean spl getbean mes ssp let scope class ons

### 準備

## 目標

了解 Spring IOC 的基礎流程

## 相關資源

Offical Doc:http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/ Sample code:<https://github.com/gordonklg/study>,spring module 源碼版本:Spring framework 4.3.9

##測試代碼

gordon.study.spring.ioc.IOC01_DefaultListableBeanFactory.java
技術分享 ioc01.xml <beans ...> <bean id="message" class="gordon.study.spring.common.Message"> <property name="body" value="Hello World!" /> </bean> </beans>

### 分析

## 整體流程分析

org.springframework.core.io.Resource 是 Spring 抽象出來的代表底層資源的接口,從這些資源可以獲得輸入流(InputStream)
。代碼第16行創建了一個 org.springframework.core.io.ClassPathResource 實例,表示是相對於類路徑的文件資源。
org.springframework.beans.factory.support.DefaultListableBeanFactory 是本次分析的核心。DefaultListableBeanFactory 實現了 org.springframework.beans.factory.BeanFactory 接口,BeanFactory 接口定義了訪問 Spring bean 容器的方法,通過該接口,我們可以從容器中獲取預先配置的 bean。
BeanFactory 接口定義了以下方法: 技術分享 BeanFactory 接口中最重要的方法就是 getBean(String),通過 bean name 獲得指定的實例。代碼第20行就是通過 getBean 方法從 bean 容器中獲得 Message 類的實例。 為了能夠從 BeanFactory 中獲取 bean 實例,BeanFactory 的實現類首先應該能獲得 bean 定義,例如本例中通過 xml 文件配置的 message bean,這就需要為 bean 定義設計一個數據模型,在 Spring 中,org.springframework.beans.factory.config.BeanDefinition 接口用來表示 bean 定義。 所有的 bean 定義應該放到同一個地方以便管理,org.springframework.beans.factory.support.BeanDefinitionRegistry 相當於 BeanDefinition 的註冊表,為 Spring IOC 提供對 BeanDefinition 的註冊、獲取操作。 技術分享 Spring IOC 框架設計時決定讓 BeanFactory 的實現類同時承擔 BeanDefinitionRegistry 的職能,所以 DefaultListableBeanFactory 實現了 BeanDefinitionRegistry 接口,同時包含一個 Map<String, BeanDefinition> beanDefinitionMap 屬性作為 BeanDefinition 的註冊表。 有了存放 BeanDefinition 的註冊表,我們還需要工具類從配置文件中讀取出 bean 定義,第18行的 org.springframework.beans.factory.xml.XmlBeanDefinitionReader 用來從 xml 格式的配置文件中讀取出 bean 定義,並將 bean 定義註冊到其構造函數指定的 BeanDefinitionRegistry 實例中(本例中為 DefaultListableBeanFactory 實例)。第19行調用 loadBeanDefinitions 方法從指定 Resource 中讀取 bean 定義。

## BeanFactory.getBean 流程分析

當程序執行到第20行準備從 bean 容器中獲取實例時,可以發現 DefaultListableBeanFactory 中已經成功讀取到 BeanDefinition 信息: List<String> beanDefinitionNames - [message] Map<String, BeanDefinition> beanDefinitionMap - {message=Generic bean: class [gordon.study.spring.common.Message]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [ioc/ioc01.xml]} 第20行 getBean 在本例中的核心流程如下:
  1. 嘗試從 singletonObjects 中獲取名字為 message 的 bean 實例
    由於 bean 默認是 Singleton 類型,所以 DefaultListableBeanFactory 中包含屬性 Map<String, Object> singletonObjects 用來緩存所有 Singleton 類型實例。只有當指定名字的 Singleton 實例尚未被創建時才會創建實例,否則直接返回已創建的實例。
  2. 將 bean 標記為已創建(或即將創建完成)狀態。就是將 bean name 放到 Set<String> alreadyCreated 中。
  3. 根據 BeanDefinition 生成 RootBeanDefinition,RootBeanDefinition 可以看做是合並過的最終 bean 定義。在本例中,RootBeanDefinition 與 BeanDefinition 基本一致,除了將原來值為空的 scope 改為 singleton。- Root bean: class [gordon.study.spring.common.Message]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [ioc/ioc01.xml]
  4. RootBeanDefinition 放到 Map<String, RootBeanDefinition> mergedBeanDefinitions 中。
  5. 流經一個很復雜的過程,根據 RootBeanDefinition 中的信息,通過反射創建出 bean 實例,並裝配好屬性,再將 bean 實例放入 Map<String, Object> singletonObjects 中。

Spring IOC 源碼簡單分析 01 - BeanFactory