从源码分析 spring application context 以及 application context 的 refresh 过程
介绍
application context 是 spring 应用的核心概念,它集多个概念于一身:
- ListableBeanFactory: bean 容器
- ResourceLoader: 资源加载器
- ApplicationEventPublisher: spring 应用事件
- MessageSource: 消息源,主要用于实现国际化
- Environment: spring 运行环境与配置
每一个 spring 应用都至少有一个 application context。不同的场景会使用不同的具体实现,而不同的实现基本上是配置方式上的不同,所具有的特性基本上是一样的。
application context 还有层次结构。子 application context 会合并父 application context 的环境配置,响应在父 application context 发布的事件等。
类层次结构
application context 基本的类层次结构如下图:
- ApplicationContext 接口就是 application context 的表示,它继承 EnvironmentCapable、 ListableBeanFactory 等多个接口(正好说明 application context 集合了多种概念)
- ConfigurableApplicationContext 按照惯例,配置性的 set 方法都放在 Configurable 接口
- AbstractApplicationContext 是 ApplicationContext 的抽象实现,使用模板方法设计模式,需要子类去实现具体的方法。它继承 DefaultResourceLoader,可以加载资源
- GenericApplicationContext 不允许多次 refresh
- AbstractRefreshableApplicationContext 允许多次 refresh
大部分场景所使用的 application context 都由 GenericApplicationContext 或 AbstractRefreshableApplicationContext 派生。例如: AnnotationConfigApplicationContext 由 GenericApplicationContext 派生, ClassPathXmlApplicationContext 由 AbstractRefreshableApplicationContext 派生。
GenericApplicationContext 和 AbstractRefreshableApplicationContext 都通过组合 DefaultListableBeanFactory 来实现 bean 容器的功能,区别是当多次 refresh 时, AbstractRefreshableApplicationContext 的 refreshBeanFactory 方法 (refresh 方法会调用到) 会重建 DefaultListableBeanFactory, 而 GenericApplicationContext 会报错。
refresh 过程
refresh 方法在 AbstractApplicationContext 类中定义,它是 application context 中最重要的方法。下面分析 refresh 的过程
1 |
|
在 refresh 的过程中, 有几个地方需要详细说明
obtainFreshBeanFactory
在 obtainFreshBeanFactory 中会调用 refreshBeanFactory,而对于 AbstractRefreshableApplicationContext 子类,refreshBeanFactory 会调用子类的 loadBeanDefinitions 加载配置。例如 AbstractXmlApplicationContext 就是在这里加载 xml 并解析配置。
prepareBeanFactory
给 bean factory 设定默认的配置
- class loader
- BeanExpressionResolver:用来解析 spring 表达式
- PropertyEditorRegistrar: 属性相关
- 添加 ApplicationContextAwareProcessor, 这个 BPP 在 bean 实例化后给 bean 注入各类 Aware 属性
- 添加 ApplicationListenerDetector, 这个 BPP 找出 ApplicationListener 类型的 bean 并注册到 application context
- 如果有 loadTimeWeaver 的话就添加 BPP LoadTimeWeaverAwareProcessor 和 ClassLoader ContextTypeMatchClassLoader
- 注册默认的 bean,包括
- environment: application context 对应的 environment
- systemProperties: 一个 Map
- systemEnvironment: 一个 Map
invokeBeanFactoryPostProcessors
实例化并调用 BeanFactoryPostProcessors (BFPP)
这个时间点,bean 都还没有初始化(除了 BFPP 本身), BFPP 可以操作 beanFacotry 达到修改 bean 的定义,添加 bean 定义(BeanDefinitionRegistryPostProcessor 就是专门做这个) 等效果
BFPP 有两个来源,1 是 AbstractApplicationContext 的 beanFactoryPostProcessors 成员,可以通过编程的方式在 application context refresh 之前通过 addBeanFactoryPostProcessor 加入; 2 是 beanFactory 中注册的 BeanFactoryPostProcessor 类型的 bean。invokeBeanFactoryPostProcessors 的过程如下:
- 将第 1 类的 BFPP 按是不是 BeanDefinitionRegistryPostProcessor 分成两类 registryProcessors 和 regularPostProcessors, registryProcessors 里的调用它们的 postProcessBeanDefinitionRegistry
- 从 beanFactory 找出实现了 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessor,排序并调用它们的 postProcessBeanDefinitionRegistry 方法
- 将第 2 步找到的 BeanDefinitionRegistryPostProcessor 全部加入到 registryProcessors
- 从 beanFactory 找出实现了 Ordered 接口的 BeanDefinitionRegistryPostProcessor(排除第2步的),排序并调用它们的 postProcessBeanDefinitionRegistry 方法
- 将第 4 步找到的 BeanDefinitionRegistryPostProcessor 全部加入到 registryProcessors
- 从 beanFactory 找出 BeanDefinitionRegistryPostProcessor(排除第2,4步的),调用它们的 postProcessBeanDefinitionRegistry
- 将第 6 步找到的 BeanDefinitionRegistryPostProcessor 全部加入到 registryProcessors
- 调用 registryProcessors 里的 BFPP 的 postProcessBeanFactory
- 调用 regularPostProcessors 里的 BFPP 的 postProcessBeanFactory
- 从 beanFactory 找出 BFPP, 按 PriorityOrdered, Ordered 和 nonOrdered 分成 3 组,分别排序并调用 postProcessBeanFactory
- 清理元数据缓存
至此 invokeBeanFactoryPostProcessors 的过程结束
registerBeanPostProcessors
在 beanFactory 中找到所有 BPP, 按 PriorityOrdered、 Ordered 和 nonOrdered 分成 3 组,分别实例化并通过 beanFactory 的 addBeanPostProcessor 方法加入到 beanFactory
finishBeanFactoryInitialization
finishBeanFactoryInitialization 主要的作用是通过 beanFactory 的 preInstantiateSingletons 方法,实例化所有的非 non-lazy-init 的单例 bean。 preInstantiateSingletons 的过程如下
- 找到所有 singleton,非 abstract,非 lazy-Init 的 bean 的 beanName
- 对每个 beanName 调用 beanFactor (AbstractBeanFactory) 的 getBean ,如果 bean 还不存在,getBean 内部会调用 createBean 创建 bean
- 获取 BeanDefinition, 解析出 bean 的类型
- 如果 bean 是一个 InstantiationAwareBeanPostProcessor(BPP 的一个子类), 尝试调用它的 postProcessBeforeInstantiation 获得一个实例(Instantiation 是实例化),如果成功,调用这个 BPP 的 postProcessAfterInitialization 并返回这个 bean 作为 createBean 的结果
- 生成 bean 的实例对象,并用 BeanWrapper (方便使用)包装起来。 有多种方式生成 bean 实例对象,例如 Supplier,FactoryMethod,通过反射的方式调用 Constructor 等, 如果有 SmartInstantiationAwareBeanPostProcessor (InstantiationAwareBeanPostProcessorr 的子类)还可以通过它自动判断用哪个 Constructor
- 对这个 BeanDefinition (不是 bean )调用 MergedBeanDefinitionPostProcessor (BPP 的子类)的 postProcessMergedBeanDefinition 方法
- 在 populateBean 里设置 bean 的属性
- 尝试调用 InstantiationAwareBeanPostProcessor (如有)的 postProcessAfterInstantiation 方法,如果 postProcessAfterInstantiation 返回 false, populateBean 就返回,不设置属性
- 从 BeanDefinition 中获取 bean 的 PropertyValues
- 尝试调用 InstantiationAwareBeanPostProcessor (如有)的 postProcessProperties 和 postProcessPropertyValues,这两个方法返回一个 PropertyValues 当作真正的 PropertyValues
- 调用 applyPropertyValues 给 bean 设置属性
- populateBean 后调用 initializeBean 对 bean 进行初始化
- 给 bean 应用 BeanNameAware 等 Aware 相关设定
- 调用 BeanPostProcessor 的 postProcessBeforeInitialization 方法
- 调用 afterPropertiesSet 和 init 方法
- 调用 BeanPostProcessor 的 postProcessAfterInitialization 方法
- 设置 DisposableBean
至此所有 non-lazy-init bean 初始化完成
FBPP 描述
1 | // 允许客户修改 application context 的 bean definition |
1 | // 在一般的 BFPP 之前调用,用于 bean definition 注册 |
BPP 描述
1 | // 可以修改新生成 bean, 例如检查注解,接口,将 bean 修改为 proxies |
1 | // 给 bean 实例化前后增加 callback |
1 | // 可以修改 bean 的类型 |
1 | // 可以合并 beanDefinition |