Spring Boot-6-refresh方法解析

前面介绍了一些Spring容器在初始化时的系统初始化器以及监听器的加载等,Spring容器创建之后,会调用它的refresh方法,refresh的时候会做很多事情:比如完成配置类的解析.各种 BeanFactoryPostProcessorBeanPostProcessor 的注册、国际化配置的初始化、web内置容器的构造等等.

本文来看一下refresh方法的具体源码,看下他具体做了哪些事情

源码跟踪

首先,run方法点进去:

image

然后找到 refreshContext() 方法,继续往下

image

image

这里就是 refresh 方法做的所有的事情,这里面一共调用了 12 个方法,而且是一个同步的代码块,也就是只能有一个线程调用,下面一个一个的看一下他们的具体作用

prepareRefresh()

代码如下:

image

这个方法做的事情主要就是:

  • 配置启动开始时间
  • 设置容器状态是active
  • 初始化属性源信息(Property)
  • 校验环境变量中的必填字段

obtainFreshBeanFactory()

源码如下:

image

这个方法比较简单,先看一下 refreshBeanFactory() 方法,如下:

image

然后是 getBeanFactory()

image

这里默认返回的BeanFactory就是 DefaultListableBeanFactory

prepareBeanFactory()

image

这里主要是对上面获取到的 BeanFactory 做一些设置,主要如下:

  • 设置classloader(用于加载bean),设置表达式解析器(解析bean定义中的一些表达式),添加属性编辑注册器(注册属性编辑器)
  • 添加 ApplicationContextAwareProcessor 这个后置处理器
  • 取消 EnvironmentAware,EmbeddedValueResolverAware,ResourceLoaderAware,ApplicationEventPublisherAware,MessageSourceAware,ApplicationContextAware 这几个接口的自动注入, 这几个接口会交给 ApplicationContextAwareProcessor 去处理
  • 设置特殊类型对应的bean, BeanFactory 对应上一步获取到的 beanFactory, 然后 ResourceLoader,ApplicationEventPublisher,ApplicationContext 这三个接口对应的bean都设置为当前的Spirng容器
  • 最后会注入一些其他信息的bean,比如 environment , systemProperties

postProcessBeanFactory()

这个方法的作用主要是 BeanFactory 设置之后再进行后续的一些 BeanFactory 操作, 这个方法在通常情况下是一个空的实现,会交给子类来实现,比如我们项目中添加了web环境的依赖,那就会交给 web 环境的实现类去实现,如下:
image

再来看一下父类的 postProcessBeanFactory 方法

image

这里就是对web环境的一些设置,注册一些web环境特有的作用域等

所以这个方法的主要作用就是:

  • 交给子类重写,以在 BeanFactory 完成创建后做进一步的设置

invokeBeanFactoryPostProcessors()

image

这里获取所有的 BeanFactoryPostProcessors 的实现,然后交给 PostProcessorRegistrationDelegate 执行他的 invokeBeanFactoryPostProcessors() 方法

这里需要知道以下两个接口:

  • BeanFactoryPostProcessor: 这个接口的作用是对Spring容器中已经存在的Bean做修改, 使用上面获取的 BeanFactory 也就是 DefaultListableBeanFactory 对 Bean 进行处理
  • BeanDefinitionRegistryPostProcessor: 这个接口继承自 BeanFactoryPostProcessor ,作用跟 BeanFactoryPostProcessor 是一样的,他是使用的 BeanDefinitionRegistry 对 Bean 进行处理

然后进入 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors() 方法看一下,这个方法比较长, 分开每个部分看:

第一部分

image

第二部分

image

第三部分

image

这里这个循环,主要是防止 BeanDefinitionRegistryPostProcessor 的实现类中,又注入了一个 BeanDefinitionRegistryPostProcessor 的实现,所以就一直循环,然后直到所有的 BeanDefinitionRegistryPostProcessor 都处理完成

流程图

前面这几部分的流程图如下:

第一部分:

image

第二部分:

image

image

第三部分:

image

继续往下看,这个方法的源码

第四部分

image

这里和上面的逻辑基本是一样的,最后会清空一个这个方法产生的缓存,然后这个方法就结束了

总结

总结一下这个方法的作用:

  • 调用 BeanDefinitionRegistryPostProcessor 的实现,向容器内添加 Bean 的定义
  • 调用 BeanFactoryPostProcessor 的实现,向容器内 Bean 的定义添加属性

registerBeanPostProcessors()

代码如下:

image

这里调用的是 PostProcessorRegistrationDelegateregisterBeanPostProcessors() 方法, 然后看一下具体的实现:

image

image

大致流程和上个方法是一样的

  1. 先找出实现了 PriorityOrdered 接口的 BeanPostProcessor 并排序后加到 BeanFactoryBeanPostProcessor 集合中
  2. 找出实现了 Ordered 接口的 BeanPostProcessor 并排序后加到 BeanFactoryBeanPostProcessor 集合中
  3. 没有实现 PriorityOrderedOrdered 接口的 BeanPostProcessor 加到 BeanFactoryBeanPostProcessor 集合中

这个方法主要作用就是:

  • 找到所有的 BeanPostProcessor 的实现
  • 排序后注册到容器中

initMessageSource()

代码如下:

image

这个方法的作用就是:

  • 在Spring容器中初始化一些国际化相关的属性

initApplicationEventMulticaster()

代码如下:

image

这方法的作用是:

  • 初始化事件广播器,注册到容器中

onRefresh()

代码如下:

image

这里是一个空的模板方法,具体的会交给子类去实现,比如我们的web环境中,就会交给子类 ServletWebServerApplicationContext 去实现,如下:

image

web环境中的 onRefresh() 方法会创建一个 web 容器,比如tomcat

registerListeners()

代码如下:

image

这里的 earlyApplicationEvents 这个集合,就是在我们容器的事件派发机制还没有完善的时候发出去的事件,都会存放在这个集合里面,然后在这一步都推送出去

所以这个类的作用就是:

  • 把Spring容器内的事件监听器和 BeanFactory 中的事件监听器都添加到事件广播器中
  • 派发早期事件

finishBeanFactoryInitialization()

这个方法的作用是:

  • 实例化 BeanFactory 中已经被注册但是未实例化的所有实例(懒加载的不需要实例化),比如 invokeBeanFactoryPostProcessors 方法中根据各种注解解析出来的类,在这个时候都会被初始化.
  • 实例化的过程各种BeanPostProcessor开始起作用

这个方法的源码放在下一章详细说明

finishRefresh()

代码如下:

image

这个方法的主要作用如下:

  • 初始化生命周期处理器
  • 调用生命周期处理器的 onRefresh() 方法
  • 发布 ContextRefreshedEvent 事件
  • JMX相关处理

总结

Spring 容器的 refresh 过程就是上述11个方法,内容比较多,每个方法都是大致写了一下流程,可以建个项目debug跟着走一下,会更清晰