【源码】SpringBoot 启动流程 (七)

65 阅读8分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

11.refreshContext

4.postProcessBeanFactory

方法上注释:Allows post-processing of the bean factory in context subclasses. 翻译过来就是:允许在上下文子类中对 bean 工厂进行后处理。

进入postProcessBeanFactory()方法,该方法在 AbstractApplicationContext 是默认空方法,在 SpringBoot 中对其进行了扩展。

进入子类AnnotationConfigServletWebServerApplicationContextpostProcessBeanFactory()方法如下:

首先是调用了父类中的 postProcessBeanFactory() 方法,其父类为 ServletWebServerApplicationContext,进入其 postProcessBeanFactory() 方法如下:

1.向 beanFactory 中添加了一个叫WebApplicationContextServletContextAwareProcessor的 bean 后置处理器。

2.向 beanFactory 的 ignoredDependencyInterfaces 中添加了一个 ServletContextAware 类型。

3.注册作用域

进入registerWebApplicationScopes()方法如下:

3.1 首先创建了ExistingWebApplicationScopes对象,在其构造方法中,首先判断了 beanFactory 的 scopes 中是否存在 request 和 session 的 scope,若存在,则保存在 ExistingWebApplicationScopes 的 scopes 属性中返回。从 beanFactory 中拿到指定 scope.

这里 DEBUG 是不存在,所以 ExistingWebApplicationScopes 的 scopes 属性为空。

3.2 调用 WebApplicationContextUtils 的 registerWebApplicationScopes() 方法来注册 scope。

进入 registerWebApplicationScopes() 方法如下:

在该方法里面注册了 request 和 session 两个 scope。

向 beanFactory 中 resolvableDependencies 添加了 4 个类型。

3.3 将 3.1 中从 beanFactory 中拿到的 scope 重新保存到 beanFactory 中。

由于 3.1 中没有拿到任何 scope,所以这里不会执行。

然后是判断了basePackagesannotatedClasses是否有值:

经过 DEBUG 发现,basePackages 和 annotatedClasses 此时都无值,所以不进行操作。

5.invokeBeanFactoryPostProcessors

Invoke factory processors registered as beans in the context. 翻译过来就是:调用在上下文中注册为 bean 的工厂处理器。

进入invokeBeanFactoryPostProcessors()方法如下:

方法上注释:Instantiate and invoke all registered BeanFactoryPostProcessor beans, respecting explicit order if given. Must be called before singleton instantiation.

翻译过来就是:实例化并调用所有注册的 BeanFactoryPostProcessor bean,如果给出,则尊重明确的顺序。必须在单例实例化之前调用。( 最后这个没明白啥意思 )

首先调用getBeanFactoryPostProcessors()方法,获取了所有的 beanFactoryPostProcessor 后置处理器,将其传入PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法,PostProcessorRegistrationDelegate 是 AbstractApplicationContext 的后置处理器处理的委托操作类。

这里getBeanFactoryPostProcessors()获取到的 beanFactory 后置处理器有如下三个:

前两个是在 10.3 步骤中加载的,第三个是在 10.9 步骤加载的。

这几个类的继承关系如下:

BeanFactoryPostProcessor 接口中只有一个postProcessBeanFactory()方法。

BeanDefinitionRegistryPostProcessor 接口中只有一个postProcessBeanDefinitionRegistry()方法。

\

进入invokeBeanFactoryPostProcessors()方法如下:

\

1.创建了一个 set 类型的 processedBeans,用来存放处理过的 bean。

2.判断当前 beanFactory 是否实现了 BeanDefinitionRegistry 接口。

我们知道,这里传入的 beanFactory 类型为 DefaultListableBeanFactory,查看其类定义,实现了该接口。

3.创建了两个 List

一个是List<BeanFactoryPostProcessor>List<BeanDefinitionRegistryPostProcessor>

regularPostProcessors存放的是 常规的 PostProcessor,即直接实现 BeanFactoryPostProcessor接口的。

registryProcessors存放的是 注册的 PostProcessor,即直接实现 BeanDefinitionRegistryPostProcessor接口的。

4.然后 for 循环对传入的 beanFactoryPostProcessors 进行处理。

在循环里面,判断当前的 postProcessor 是否实现了 BeanDefinitionRegistryPostProcessor 接口:

如果是,则对其进行类型转换,然后调用其postProcessBeanDefinitionRegistry()方法,这里传入的参数 registry,其实就是 beanFactory。然后添加到 registryProcessors 中。

如果不是,则不执行任何操作,直接添加到 regularPostProcessors 中。

这里有三个 beanFactoryPostProcessors,我们分别来看:

4.1 CachingMetadataReaderFactoryPostProcessor

首先遍历的是 CachingMetadataReaderFactoryPostProcessor,其实现了 BeanDefinitionRegistryPostProcessor 接口。所以会进入它的postProcessBeanDefinitionRegistry()方法如下:

首先是 register() 方法,如下:

SharedMetadataReaderFactoryBean注册到了 beanDefinitionMap 中,key 见上图。

然后是 configureConfigurationClassPostProcessor() 方法,如下:

从 beanDefinitionMap 中获取指定 key 的 beanDefinition,并为其propertyValues属性设置 metadataReaderFactory 属性的值。

propertyValues 是个 List,而每个元素,又是一个 Map.

运行后,beanDefinitionMap 如下:

4.2 ConfigurationWarningsPostProcessor

接着遍历的是 ConfigurationWarningsPostProcessor,其实现了 BeanDefinitionRegistryPostProcessor 接口。所以会进入它的postProcessBeanDefinitionRegistry()方法如下:

遍历 checks,并调用其 getWarning()方法,进行校验,如果存在 warn 信息,则输出日志。

这里的 checks 只有一个,是 ComponentScanPackageCheck

它是在 创建 ConfigurationWarningsPostProcessor 对象时,创建了 ComponentScanPackageCheck 对象,并赋值给 checks 的。

进入 ComponentScanPackageCheck 的 getWarning() 方法如下:

方法里面首先调用getComponentScanningPackages()方法获取了需要扫描的包 scanedPackages。然后调用 getProblematicPackages()方法,过滤出有问题的扫描包路径 problematicPackages,最后判断如果真的存在,给出日志。

getComponentScanningPackages() 方法如下:

遍历 beanDefinitionMap,此时有 7 个元素,而启动类就包含在其中。如果是 AnnotatedBeanDefinition 类型的 BeanDefinition 时,就获取该类上的 @ComponentScan注解,得到扫描包路径。这里可能得到多个扫描路径。

getProblematicPackages() 方法如下,就是判断了这些扫描的包路径是否存在问题。

PROBLEM_PACKAGES 则是静态代码块中加载的。

4.3 PropertySourceOrderingPostProcessor

没有实现 BeanDefinitionRegistryPostProcessor 接口,未执行。

5.处理实现了 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessor

创建了一个List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors用来保存当前需要处理的 BeanDefinitionRegistryPostProcessor。每处理完一种分类的就清空。

根据 BeanDefinitionRegistryPostProcessors 实现的接口,将其划分为三类:实现了 PriorityOrdered 接口的、实现了 Ordered 接口的,一个都没实现的。其处理的先后顺序为:PriorityOrdered > Ordered > No

先来看处理 PriorityOrdered 的:

5.1 从 beanFactory 中获取 BeanDefinitionRegistryPostProcessor 类型的 beanName 数组。

此时的 beanDefinitionMap 中依旧是只有 7 个 bean,如下:

而符合条件的 beanName 只有一个:

其对应的 bean 的 class 类型为:

该 ConfigurationClassPostProcessor 类定义如下:

5.2 判断获取到的 指定 key 的 bean 是否实现了 PriorityOrdered 接口

如果是,则从 beanFactory 中获取该 bean,然后添加到 currentRegistryProcessors 当前处理的 processor 列表中,并添加到 processedBeans 已处理的列表中。

此时 currentRegistryProcessors 中的元素如下:

5.3 对 currentRegistryProcessors 按照优先级进行排序

5.4 将其添加到 registryProcessors 列表中。

registryProcessors 存放的是直接实现 BeanDefinitionRegistryPostProcessor 接口的。

5.5 传入 currentRegistryProcessors,循环调用其postProcessBeanDefinitionRegistry()方法

这里只有 ConfigurationClassPostProcessor,其 postProcessBeanDefinitionRegistry() 方法调用见单独文章,ConfigurationClassPostProcessor

这个 PostProcessor 可以说是 SpringBoot 中最重要的一个 BeanFactoryPostProcessor,它负责将项目中所有注册的 bean 解析为 beanDefinition,当该 后置处理器执行完毕后,此时查看 beanFactory 中的 beanDefinitionMap 如下:

可以看到,现在已经有 900+ 个 beanDefinition 了,而在 ConfigurationClassPostProcessor 的 postProcessBeanDefinitionRegistry() 方法执行之前,只有 7 个。

需要注意的是:这里只是创建了 BeanDefinition 对象,并没有创建其对应的 Bean 对象。

5.6 清空 currentRegistryProcessors 列表。

6..处理实现了 Ordered 接口的 BeanDefinitionRegistryPostProcessor

代码如下:

和处理实现了 PriorityOrdered 接口的逻辑基本一致,不同的是:

6.1 这里再次通过 beanFactory 获取了 postProcessorNames,为什么再次获取呢,之前不是已经获取过了吗?这是因为,前面处理的时候有可能又加入了新的 BeanDefinitionRegistryPostProcessor,所以这里重新进行了获取。

6.2 在循环时,判断了是否被处理,只有没有被处理,并且实现了 Ordered 接口,才会进行后续操作。

这里在 DEBUG 时发现,获取到的 postProcessorNames 依旧只有 ConfigurationClassPostProcessor,而其已经处理过了,所以这块实际上没有执行任何操作。

\

7.最后是处理没有实现上面两个接口的 BeanDefinitionRegistryPostProcessor

代码如下:

使用一个 while 循环来处理,因为每次处理,都有可能增加 BeanDefinitionRegistryPostProcessor。

这里在 DEBUG 时发现,获取到的 postProcessorNames 依旧只有 ConfigurationClassPostProcessor,而其已经处理过了,所以这块实际上没有执行任何操作。

8.调用 postProcessBeanFactory() 方法

两个列表中的元素如下:

进入invokeBeanFactoryPostProcessors()方法,

内部循环调用了 postProcessBeanFactory() 方法。( 注意和前面区分,调用的方法不同 )

首先调用了直接实现 BeanDefinitionRegistryPostProcessor接口的。因为BeanDefinitionRegistryPostProcessor 继承了 BeanFactoryPostProcessor,也具有 postProcessBeanFactory() 方法的,所以也需要执行。

然后调用了直接实现 BeanFactoryPostProcessor接口的。

下面来看看具体每个 postProcessBeanFactory() 方法执行的操作:

1.CachingMetadataReaderFactoryPostProcessor 的 postProcessBeanFactory() 方法是个空方法。

2.ConfigurationWarningsPostProcessor 的 postProcessBeanFactory() 方法是个空方法。

3.ConfigurationClassPostProcessor 的 postProcessBeanFactory() 方法,则是和自动配置有关。

4.PropertySourceOrderingPostProcessor 的 主要作用是对默认的配置文件进行排序,如果存在的话,就将其放在最后一位。这里 DEBUG 是没有的。

9.处理 BeanFactoryPostProcessor

在前面的逻辑执行后,已经有 900+ 个 beanDefinition 了,可能会添加新的 BeanDefinitionRegistryPostProcessor 接口的实现,在上面已经处理过了,但是还没有处理可能会增加的 BeanFactoryPostProcessor 的实现,这里的逻辑便是进行这个操作的。

代码如下:

9.1 从 beanFactory 中获取 BeanFactoryPostProcessor 的实现。

DEBUG 结果如下,共 7 个元素:

9.2 创建了三个 List

priorityOrderedPostProcessors存放实现了 PriorityOrdered 接口的 bean 对象,

orderedPostProcessorNames 存放实现了 Ordered 接口的 beanName

nonOrderedPostProcessorNames 存放没有实现上面两个接口的 beanName

至于为什么,有的存放 bean,有的存放 beanName,暂且不知。

9.3 循环处理,对已经处理过的 processedBeans,不再执行。

DEBUG 结果如下:

10.和上面一样,也是先执行实现了 PriorityOrdered 接口的 BeanFactoryPostProcessor,对其排序后,循环调用其 postProcessBeanFactory() 方法。

PropertySourcesPlaceholderConfigurer 的 postProcessBeanFactory() 方法。具体流程见:PropertySourcesPlaceholderConfigurer

11.执行实现了 Ordered 接口的 BeanFactoryPostProcessor

从 beanFactory 中获取其 bean 对象,排序后,循环执行 postProcessBeanFactory() 方法。

\

12.执行未实现这两个接口的 BeanFactoryPostProcessor

从 beanFactory 中获取其 bean 对象,循环执行 postProcessBeanFactory() 方法。

没有执行排序操作?为什么?

\

13.清空缓存

清空缓存的 merged beanDefinition

进入clearMetadataCache()方法如下:

首先调用了父类 AbstractBeanFactoryclearMetadataCache()方法,如下:

从 mergedBeanDefinitions 中,移除不存在于 alreadyCreated 中的元素。

DEBUG 可知,在清除之前,mergedBeanDefinitions 存在 926 个元素:

alreadyCreated 中存在 12 个元素如下:

所以最后 mergedBeanDefinitions 只剩余 12 个元素。

然后调用 clearByTypeCache() 方法:

这里的 allBeanNamesByType,singletonBeanNamesByType 都为空。