万字+20张图剖析Spring启动时核心的12个步骤

laomugua
发布于 2023-11-6 15:05
浏览
0收藏

invokeBeanFactoryPostProcessors

从这个方法的名字可以看出,是调用BeanFactoryPostProcessor,这个步骤非常重要,而且过程有点绕

前置知识:BeanFactoryPostProcessor及其子接口

BeanFactoryPostProcessor是一个接口,有一个方法,方法参数就是BeanFactory

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

通过这个方法就可以拿到BeanFactory,然后对BeanFactory做一些自己的调整

比如说,你想关闭循环依赖,你就可以实现这个接口,然后进行调整

他还有一个子接口BeanDefinitionRegistryPostProcessor

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

这个接口是对BeanDefinitionRegistry进行调整,BeanDefinitionRegistry就是存BeanDefinition的地方,真实的实现就是DefaultListableBeanFactory

所以BeanDefinitionRegistryPostProcessor的作用就是往BeanDefinitionRegistry(DefaultListableBeanFactory)中添加BeanDefinition的

再看invokeBeanFactoryPostProcessors

有了这两个前置知识之后,我们来看看invokeBeanFactoryPostProcessors方法的实现

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

这个方法最终会调用下面方法来真正的处理

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors;

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

这个方法比较长,大致分为两件事

  • 调用所有的BeanDefinitionRegistryPostProcessor,解析配置类,注册BeanDefinition到DefaultListableBeanFactory中
  • 从BeanFactory中获取所有的BeanFactoryPostProcessor进行调用,完成对BeanFactory一些其它的扩展
调用BeanDefinitionRegistryPostProcessor

首先第一步,先从BeanFactory中获取到所有的BeanDefinitionRegistryPostProcessor对象,调用它的postProcessBeanDefinitionRegistry方法

还记得上一节在说注册Spring内部的Bean时特地强调的一个类ConfigurationClassPostProcessor不?

他就实现了BeanDefinitionRegistryPostProcessor接口

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

所以此时获取到的就是ConfigurationClassPostProcessor

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

获取ConfigurationClassPostProcessor的时候会走Bean的生命周期,也就是会回调前面添加的BeansPostProcessor,但是也没几个

之后会调用他的postProcessBeanDefinitionRegistry方法,来处理此时BeanFactory中的配置类

配置类从哪来,前面一直没提到过

但是看一下ApplicationContext是如何使用的就知道了

比如说,下面这个demo

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

在创建一个ApplicationContext之后,在注册一个Bean之后再refresh

此时这个注册的Bean就是配置类。

如果你不注册,那是真没有配置类,此时也就没什么意义了。

所以,ApplicationContext一定会有一个配置类,不然没有意义。

在SpringBoot条件下,SpringBoot在启动时就会将启动引导类当做配置类给扔到BeanFactory中。

所以ConfigurationClassPostProcessor最开始处理的时候,就是处理启动引导类

我们可以在ConfigurationClassPostProcessor方法实现上打个断点验证一下

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

在处理之前可以看见,除了几个spring内部的BeanDefinition之外,还有一个myApplication,就是我的启动引导类

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

处理的时候它会解析启动引导类的注解,进行自动装配,扫描你写的代码的操作,之后生成BeanDefinition

当处理完成之后我们再看看,DefaultListableBeanFactory有了非常多的BeanDefinition了

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

所以到第一步就完成了,此时BeanFactory就加载了很多Bean

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

接下来,由于又新注册了很多BeanDefinition,而这些里面就有可能有BeanDefinitionRegistryPostProcessor接口的实现

所以之后会重复从BeanFactory中获取BeanDefinitionRegistryPostProcessor,调用postProcessBeanDefinitionRegistry

一直会循环下去,直到所有的BeanDefinitionRegistryPostProcessor都被调用为止

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

由于BeanDefinitionRegistryPostProcessor继承BeanFactoryPostProcessor

所以之后也会调用BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法

调用BeanFactoryPostProcessor

当调完所有的BeanDefinitionRegistryPostProcessor实现方法

之后就会从BeanFactory获取所有的BeanFactoryPostProcessor(除了BeanDefinitionRegistryPostProcessor实现之外),调用postProcessBeanFactory方法

此时就可以通过BeanFactoryPostProcessor再次对BeanFactory进制扩展

总的来说,这一步骤的核心作用就是完成对BeanFactory自定义扩展,但是由于BeanFactoryPostProcessor都是Bean,所以要第一步先加载Bean,之后才能通过BeanFactoryPostProcessor来扩展

一张图来总结上面主要干的事

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

这里简化了一些前面提到东西

registerBeanPostProcessors

上面一个步骤已经完成了Bean的扫描和对BeanFactory的扩展

这一节通过方法名就可以看出,是跟BeanPostProcessor相关

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

不过在这个方法执行之前,我们先来看看此时BeanFactory中已经有了哪些BeanPostProcessor

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

此时只有4个,前3个前面都提到过,但是像我们熟知的处理@Autowired、@Resource注解的BeanPostProcessor都不在里面

所以这里就有一个非常重要的小细节

在当前这个步骤执行之前如果从BeanFactory中获取Bean的话,虽然会走Bean生命周期的整个过程,但是@Autowired、@Resource注解都不会生效,因为此时BeanFactory中还没有处理这些注解的BeanPostProcessor(CommonAnnotationBeanPostProcessor等)

什么意思呢,举个例子

比如上面一节,在当前步骤执行之前会从BeanFactory中获取BeanFactoryPostProcessor

假设现在你实现了BeanFactoryPostProcessor,想注入一个ApplicationContext对象

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

此时是注入不成功的,@Resource注解不会生效,就是这个意思。

这时只能通过ApplicationContextAware方式获取,因为有对应的BeanPostProcessor(ApplicationContextAwareProcessor)

接下来我们再来看看registerBeanPostProcessors实现

最终也是调用下面的方法

PostProcessorRegistrationDelegate#registerBeanPostProcessors

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

这个过程就没上面那个步骤复杂了

其实就是从BeanFactory中获取到所有的BeanPostProcessor,然后添加到BeanFactory中

不过值得注意的是,BeanPostProcessor创建会有优先级,优先级高的会先被创建和添加到BeanFactory中

到这一步其实BeanFactory就算是准备完成了,基本上跟创建Bean相关的前置操作几乎都完成了

最后再来张图总结一下这个方法干的事

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

initMessageSource

这个方法是处理国际化相关的操作

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

这个操作比较简单,就是从BeanFactory中看看有没有Bean名称为messageSource的Bean

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

有的话就使用这个MessageSource,没有的话就用默认的

不过SpringBoot项目下会自动装配一个MessageSource,所以此时容器中是有的

initApplicationEventMulticaster

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

这个方法跟上面的差不多,也是从BeanFactory找有没有ApplicationEventMulticaster

有就用容器中的,没有就自己创建一个

ApplicationEventMulticaster是真正用来发布事件的,ApplicationEventPublisher最终也是调用他来发布事件

ApplicationEventMulticaster内部会缓存所有的监听器

当通过ApplicationEventMulticaster发布事件的时候,会去找到所有的监听器,然后调用

onRefresh

onRefresh也是一个模板方法,本身也是空实现

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

子类重写这个方法,会去创建一个Web服务器

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

registerListeners

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

这个方法其实也比较简单,就是将监听器给添加到ApplicationEventMulticaster中

finishBeanFactoryInitialization

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

这个方法首先又是老套路,就是判断容器中有没有ConversionService

ConversionService也是用来做类型转换的,跟前面提到的PropertyEditor作用差不多

如果有,就把ConversionService设置到BeanFactory中

到这一步,BeanFactory才算真的准备完成。。。

之后其实干的事就不太重要了

但是最后一行比较重要

beanFactory.preInstantiateSingletons();

从方法的命名就可以看出,实例化所有的单例对象

因为对于BeanFactory的一些配置在前面都完成了,所以这里就可以来实例化所有的单例对象了

这个方法会做两件事

第一件事就是实例化所有的非懒加载的单例Bean

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区

实际上就是通过getBean方法来的,因为获取Bean,不存在的时候就会创,会走Bean的生命周期

第二件事就是一旦单例Bean实现了SmartInitializingSingleton接口,就会调用SmartInitializingSingleton的afterSingletonsInstantiated方法

万字+20张图剖析Spring启动时核心的12个步骤-鸿蒙开发者社区


文章转载自公众号:三友的java日记

标签
已于2023-11-6 15:05:13修改
收藏
回复
举报
回复
    相关推荐