上文 其實咱們已經實現了一個簡單的 BeanFactory
它具的功能有html
其實總結起來它實現的方法就是:加載 Bean 定義、實例化 Bean,很簡單吧java
Bean 在 spring 中的完整生命週期,能夠自行查看spring 的 BeanFactory
接口,它在最上面的註釋有詳細說明。git
但實際的應用場景除了這個主要 Bean 管理外,還有一些消息廣播、國際化、事件監聽等spring
本文想分析下 ApplicationContext
的 refresh
過程,先來個總結性的過程,以便後續一堆枯燥的源碼分析數據庫
BeanFactory
,這裏初始化的是 DefaultListableBeanFactory
BeanFactory
像 spel 表達式解析器、Environment
都要配置到工廠裏面,以便後續的處理BeanFactoryProcessor
來修改 BeanFactory
中的 Bean ,經常使用的子類 BeanDefinitionRegistryPostProcessor
它能夠往容器中添加 Bean 定義像 @Import、@PropertySource、@ComponentScan、@ImportResource、@Bean methods 還有 tk.mybatis 都是靠它來注入自定義的 Bean 定義 的,不清楚什麼是 bean 定義看個人 上篇文章springboot
BeanFactoryProcessor
了BeanPostProcessor
,這些 processor
是已經加到容器中的,若是你看到這裏,不懂什麼是 BeanPostProcessor
請回頭看 上文 的 bean 的生命週期,不清楚回調那就沒辦法了,你還不夠經驗看這篇文章不會把每一步都細品,只會對一些關鍵的步驟進行解讀,像如何加載 Bean 定義,讀 xml 和讀註解的,讀者能夠自行研讀,本文討論幾個關鍵的 processor mybatis
咱們都知道,Bean 的生命週期中,能夠添加 BeanPostProcessor
在 bean 的初始化前和初始化後作一些處理,一樣的在 BeanFactory 也有一個 BeanFactoryPostProcessor
容許你在 BeanFactory 初始化後,修改 BeanFactory。app
樣例:框架
咱們看一下 PropertyPlaceholderConfigurer
xml 配置時代的產物, 它的繼承結構以下maven
PropertyResourceConfigurer implements BeanFactoryPostProcessor |-PlaceholderConfigurerSupport |-PropertyPlaceholderConfigurer
咱們一般會在最開始配置這個
<context:property-placeholder location="classpath:jdbc.properties" />
PropertyPlaceholderConfigurer
用於對項目中的 @Value
值進行處理,把值注入進屬性中,下面看下它如何實現的
查看關鍵方法 PropertyResourceConfigurer.postProcessBeanFactory
,分爲三步
Properties mergedProps = mergeProperties(); // 從 location 中加載屬性 // Convert the merged properties, if necessary. convertProperties(mergedProps); //什麼都沒幹,一個模板方法,可用於密碼加密,自定義屬性轉換 // Let the subclass process the properties. processProperties(beanFactory, mergedProps); // 真正處理屬性的地方,解析 spel 表達式 ${}
真正的處理過程使用了訪問者模式在 BeanDefinitionVisitor
中。
springboot 又是怎麼處理的呢,springboot 是固定了配置文件 application.properties ,而再也不使用 location 來配置路徑,它使用了 PropertySourcesPlaceholderConfigurer
來解析配置 ,它一樣繼承自 PlaceholderConfigurerSupport
而且重寫了 postProcessBeanFactory 關鍵方法,在最後面使用了
PropertySourcesPropertyResolver
進行了屬性解析。
使用方式能夠在 這篇文章 看到
BeanDefinitionRegistryPostProcessor
繼承自 BeanFactoryPostProcessor
它的參數是 BeanDefinitionRegistry
一個 Bean 定義 的註冊器,它能夠作些什麼呢 ,查看它的方法,能夠對 bean 定義作增刪改查,厲害吧。
registerBeanDefinition removeBeanDefinition getBeanDefinition containsBeanDefinition getBeanDefinitionNames getBeanDefinitionCount isBeanNameInUse
樣例一:
在 ConfigurationClassPostProcessor
中,它實現了 BeanDefinitionRegistryPostProcessor
,它使用 ConfigurationClassParser
來解析項目中配置的 @Configuration
類,而後使用 ConfigurationClassBeanDefinitionReader
把解析到的類加載到 Bean 定義
具體細節查看 這篇文章
樣例二:
在 tkmybatis 的 MapperScannerConfigurer
中,也實現了 BeanDefinitionRegistryPostProcessor
,它使用 ClassPathMapperScanner
來掃描 Mapper 類,添加進容器
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner
劃重點
其實總結來講,refresh 的過程只是給你提供了一個大體的執行框架,具體的處理仍是在一些 processor,listener 中,網上有大部分源碼解讀都拿這個 refresh 過程作大篇幅的講解,其實沒多大必要,就像 servlet 的生命週期同樣,瞭解其執行過程,但剩下的處理都是子類去具現化的。
分享一篇說得不錯的文章
BeanPostProcessor和BeanFactoryPostProcessor淺析以及在spring初始化中回調
創做不易,但願能夠支持下個人開源軟件,及個人小工具,歡迎來 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-maven