上文 其实咱们已经实现了一个简单的 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