Spring源码分析系列-Bean的生命周期(总结篇)

Posted 黄智霖-blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码分析系列-Bean的生命周期(总结篇)相关的知识,希望对你有一定的参考价值。

ApplicationContext和BeanFactory

  BeanFactory是Spring中的顶层接口,只负责管理bean,而ApplicationContext也实现了BeanFactory,提供了管理bean的功能,不过除了管理bean之外,它还提供了一些其它功能,比如依赖注入、事件发布等。只是ApplicationContext的bean管理功能也是通过BeanFactory提供的,在实现上就是ApplicationContext持有一个BeanFactory的引用,比如GenericApplicationContext中持有一个DefaultListableBeanFactory类型的beanFactory引用。

BeanDefinitionReader和BeanDefinitionRegistry

  在Spring容器中,一个Bean会首先被组装成一个BeanDefinition,然后将其注册到容器中,之后才会被实例化和初始化。Spring将这个过程细化成了很多步骤,在这些步骤中穿插了很多的后置处理器(PostProcessor)对各个环节进行拦截和扩展,以此实现了Spring极高的扩展性。
  对于BeanDefinitionRegistry来说,它提供了注册BeanDefinition的接口,实现该接口表示了其具备注册BeanDefinition的能力。而BeanDefinitionReader的存在则为根据资源批量注册BeanDefinition提供了可能。从代码层面上看,就是BeanDefinitionReader能够通过loadBeanDefinitions方法根据一系列的Resource,创建BeanDefinition,然后通过BeanDefinitionRegistry进行注册。从面向对象的角度来看,就是BeanDefinitionReader依赖一些资源(Resource)创建BeanDefinition,并且依赖BeanDefinitionRegistry实现BeanDefinition的批量注册。
  不过在Spring源码对于BeanDefinitionReader的注释中有明确的说明,BeanDefinitionReader虽然作为一个顶层接口提供了从资源批量创建注册BeanDefinition的接口。但是在具体的实现中,一个BeanDefinitionReader并不一定非要实现BeanDefinitionReader接口,而是在命名上遵循这个标准命名约定就行了,所以在实现上也可能并不是严格按照BeanDefinitionReader中定义的接口来进行BeanDefinition的注册的,Spring没有严格限制BeanDefinition注册的来源和方式,不论是对自己还是对开发者。
  比如以我们最熟悉的AnnotatedBeanDefinitionReader来说,它是一个BeanDefinitionReader,但是实际上它并没有实现BeanDefinitionReader接口。在它的逻辑中,向BeanFactory注册了一些初始的PostProcessor,依赖这些PostProcessor来代替以前XML相关的操作。
  比如在非Web环境下,我们如果要基于注解来使用Spring,则会创建一个AnnotationConfigApplicationContext,并且传入一个配置类。在AnnotationConfigApplicationContext的逻辑中就会创建一个前面提到的AnnotatedBeanDefinitionReader,而在AnnotatedBeanDefinitionReader初始化的过程中,会向容器注册了一个很重要的BeanDefinitionRegistryPostProcessor:ConfigurationClassPostProcessor。这个PostProcessor负责解析我们传入的配置类,比如解析@ComponentScan注解,然后根据ClassPathBeanDefinitionScanner从@ComponentScan注解配置的扫描包路径中扫描出合法的资源,最后创建BeanDefinition,注册到容器中,这个相当于是一个"另类"的BeanDefinition创建和注册逻辑,而这个逻辑会在后面的源码分析中详细总结。

Bean的生命周期

概述

  一个被Spring管理的Bean,在加载之后首先会被包装成一个BeanDefinition,BeanDefinition代表了Spring中一个Bean的各种基础属性(元数据),比如beanName、作用域、是否懒加载、所属类class、自动装配类型等等,同时还包含了初始化、依赖注入等需要的数据,Spring根据BeanDefinition来实例化和初始化bean。
  类被包装成BeanDefinition之后,会存放在BeanFactory的一个ConcurrentHashMap结构的beanDefinitionMap中,key为bean的名称,value为BeanDefinition。Spring容器在刷新的时候,会首先把所有的BeanDefinition都创建缓存完毕,然后调用一系列的后置处理器对其进行加工,此处和BeanDefinition相关的后置处理器主要有两种,分别是:

  • BeanFactoryPostProcessor
  • BeanDefinitionRegistryPostProcessor:继承了BeanFactoryPostProcessor

  首先,通过BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法可以向BeanFactory中继续注册BeanDefinition,之后通过BeanFactoryPostProcessor可以将BeanFactory中的BeanDefinition中取出来做进一步的加工,当这两种后置处理器处理完成之后,会冻结所有已经注册的BeanDefinition的元数据,这表示这些已经注册的BeanDefinition的元数据信息不能再被修改,接下来就要开始实例化。
  现在有了BeanDefinition,就代表有了创建Bean的模板,就可以开始创建非懒加载的单例Bean了,在创建Bean的过程中也有几个关键相关的后置处理器调用,分别是:

  • BeanPostProcessor
  • MergedBeanDefinitionPostProcessor:继承了BeanPostProcessor
  • InstantiationAwareBeanPostProcessor:继承了BeanPostProcessor

  接下来进入创建bean的流程:循环BeanFactory中的BeanDefinitionMap,实例化所有单例bean,在这个过程中会先把beanName放入到一个Set中标识当前bean正在创建(此处涉及到循环依赖和三级缓存的问题,这个后面再进行详细说明),然后循环调用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法(这里还涉及到AOP的部分实现,后面再详细说明)拦截bean的实例化,如果有某一个InstantiationAwareBeanPostProcessor返回了一个实例对象,那么就说明bean的实例化被拦截了,那么接着循环调用BeanPostProcessor的postProcessAfterInitialization方法,这时候代表实例对象创建成功,并且完成了初始化。
  否则说明bean的实例化没有被拦截,那么根据BeanDefinition获取Bean的构造方式进行对象的实例化,这个实例化的过程很复杂,涉及到构造器推断等,这里面也涉及到后置处理器的调用,比如构造器函数上的@Autowired支持和方法上的@Lookup注解支持都是在这里实现的,涉及到的是AutowiredAnnotationBeanPostProcessor的determineCandidateConstructors方法调用。这个方法实际上归属于SmartInstantiationAwareBeanPostProcessor,包括三级缓存中的getEarlyBeanReference方法也属于这个后置处理器,它是后置处理器InstantiationAwareBeanPostProcessor的一个扩展。实例化之后会循环调用所有MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法,在这个后置处理器中可以根据实例化之后的对象对BeanDefinition进行进一步的扩展, 这个行为发生在对象实例化之后,初始化之前,所以可以为后续的初始化操作准备一些必要的数据,同时也支持修改BeanDefinition中的部分数据,比如@Autowired注解支持的AutowiredAnnotationBeanPostProcessor后置处理器在这里对@Autowired进行预解析,找到并缓存需要注入的点。

注:此时生产出来的bean还只是一个"空的",还没有进行任何初始化操作,称之为早期对象,会将其放入三级缓存中,这个概念在解决循环依赖的实现中有着重要作用,注意三级缓存存放的不是bean,而是一个函数接口~

  接下来对bean进行属性填充(populateBean),不过在填充之前,还会循环调用所有InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation,允许在Bean实例化之后对Bean的属性填充进行拦截,该方法返回值为布尔类型,如果有任何一个InstantiationAwareBeanPostProcessor的该方法处理bean的时候返回false,那么会中断后续的bean属性填充操作。通过这个后置处理器可以实现对bean中的字段做自定义填充,不过这个在日常工作中基本不会使用,在spring源码中实现该方法的类都默认返回的true。如果没有被postProcessAfterInstantiation方法拦截,那么就会进行bean的属性填充操作。属性填充的过程是先将需要的数据封装成一个PropertyValues,然后调用所有InstantiationAwareBeanPostProcessor的postProcessProperties方法和postProcessPropertyValues方法对PropertyValues在应用到bean之前进行进一步的加工和合法性判断等,然后将PropertyValues应用到bean中。
  在bean的属性填充之后,就来到了真正开始正式初始化bean的环节,而在初始化bean之前,会先调用容器默认的3个Aware方法,分别是BeanNameAware、BeanClassLoaderAware和BeanFactoryAware,如果bean实现了这三个接口,那么会带着各自的参数调用它们各自的方法。接着调用所有BeanPostProcessor的postProcessBeforeInitialization方法,该方法允许对已经经过属性填充的bean进行进一步包装或者属性更新和扩展,方法返回值就是后续需要使用的bean,如果有任何一个处理器返回null,那么后续的处理器都不会被调用,比如@PostConstruct注解标识的初始化方法就是依赖该后置处理器实现的。接下来调用bean的初始化方法,bean的初始化方法除了刚刚提到的使用@PostConstruct注解标识外,还可以通过实现InitializingBean接口和xml中指定init-method方法,所以在通过后置处理器处理了@PostConstruct注解之后,就需要调用通过另外两种方式指定的初始化方法,顺序是先执行InitializingBean接口的afterPropertiesSet方法,再调用指定的init-method方法,当然如果init-method方法就是afterPropertiesSet,则只会调用一次。
  到这里一个bean就算实例化+初始化完成了,那么接下来调用所有BeanPostProcessor的postProcessAfterInitialization方法,这个方法又允许对已经初始化后的bean做进一步的包装处理,比如创建动态代理(注意这里是普通情况下的动态代理,如果循环依赖遇上了动态代理,那么动态代理在三级缓存中就创建了)。到这步就表示bean已经初始化完成,如果该bean实现了DisposableBean、AutoCloseable接口或者指定了destroyMethod等支持容器回调bean的销毁方法,那么就将该bean包装成一个DisposableBeanAdapter,放到一个名为disposableBeans的LinkedHashMap中,在容器关闭的时候会调用bean的销毁方法。
  最后,如果bean实现了SmartInitializingSingleton接口,那么还会调用SmartInitializingSingleton的afterSingletonsInstantiated方法。

注: 对于FactoryBean来说,容器刷新的以后在单例缓存池中保存的实例对象为原对象,而当调用getBean获取该对象的时候,如果发现该对象是一个FactoryBean,那么会尝试去从factoryBeanObjectCache缓存池中获取真实的bean,如果没有获取到,那么调用getBean方法创建真实对象,然后将该对象放入到factoryBeanObjectCache缓存池,之后直接从缓存中获取。如果要获取原对象,那么在调用getBean的时候在传入的beanName前面加上"&"字符,spring会根据该字符判断是获取真实对象还是原对象。在spring中实现BeanFactory注册和管理功能的类是FactoryBeanRegistrySupport,而我们所使用的BeanFactory继承了这个抽象类,所以具备这能力。 在Spring的类体系中,将很多行为都抽象为了一个一个的接口或者抽象类,一个类如果想要具备某个行为能力,那么就继承对应的抽象类或者实现对应的接口。

  最后就是bean的销毁流程,这个发生在容器关闭的时候,在销毁的时候也涉及到后置处理器的调用:DestructionAwareBeanPostProcessor(继承自BeanPostProcessor)。那么销毁流程是怎么样的呢?我们以实现DisposableBean接口为例,在前面已经提到过,在bean初始化完成之后,如果bean实现了DisposableBean接口,那么会将bean包装成一个DisposableBeanAdapter缓存到disposableBeans中,容器在关闭的时候,会将disposableBeans中的bean都取出来,调用其destroy方法,而在DisposableBeanAdapter的destroy方法中,就会调用所有DestructionAwareBeanPostProcessor的postProcessBeforeDestruction方法,@PreDestroy注解就是依赖该后置处理器实现的,最后调用bean的destroy方法完成bean的销毁。

bean生命周期总结

  1. 扫描class创建BeanDefinition
  2. BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
  3. BeanFactoryPostProcessor#postProcessBeanFactory
  4. InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(实例化之前,可以拦截bean的实例化)
  5. 实例化bean
  6. MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition(根据实例化bean进一步扩展BeanDefinition,比如解析缓存需要依赖注入的属性等)
  7. InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation(实例化之后,可以拦截属性填充):该方法在populateBean方法中调用
  8. bean属性填充:populateBean方法,先通过InstantiationAwareBeanPostProcessor的postProcessPropertyValues方法将需要注入的属性值封装到PropertyValues的pvs中,然后通过applyPropertyValues方法设置到实例对象中
  9. 三个Aware接口的调用,分别是BeanNameAware、BeanClassLoaderAware和BeanFactoryAware(还有很多其他Aware是通过后置处理器ApplicationContextAwareProcessor的postProcessBeforeInitialization实现的)
  10. BeanPostProcessor#postProcessBeforeInitialization(初始化之前,@PostConstruct注解在这里实现)
  11. 执行InitializingBean接口的afterPropertiesSet方法
  12. 执行xml指定的init-method
  13. BeanPostProcessor#postProcessAfterInitialization(初始化之后,可以在这里创建bean的代理)
  14. 如果bean支持销毁回调,包装DisposableBeanAdapter并缓存
  15. SmartInitializingSingleton#afterSingletonsInstantiated方法(该方法在单例bean完全初始化完成后调用,用于实现最后阶段的自定义初始化操作,可以看做是InitializingBean的替代方案)
  16. bean销毁
  17. 取出前面缓存的DisposableBeanAdapter调用其destroy方法,在这个适配器的destroy方法中会触发DestructionAwareBeanPostProcessor的postProcessBeforeDestruction方法执行
  18. 调用DisposableBean的destroy方法
  19. 调用destroyMethod

注:Spring依赖注入主要依靠了后置处理器AutowiredAnnotationBeanPostProcessor,它相当于一个复合后置处理器,实现了多个后置处理器的行为,穿插运行于bean生命周期的几个阶段。比如,determineCandidateConstructors方法(实例化之前):解析@Lookup注解,检查构造方法中的 @Autowired或@Value注解;postProcessMergedBeanDefinition(实例化之后,populateBean之前):执行findAutowiringMetadata逻辑,收集@Autowired或@Value注解方法字段等存入缓存;postProcessPropertyValues(实例化之后,populateBean):处理依赖注入对象,为属性赋值做准备等

Spring容器核心方法之invokeBeanFactoryPostProcessors方法

  这个方法主要做的工作就是先调用BeanDefinitionRegistryPostProcessor,再调用BeanFactoryPostProcessor,只是调用的时候会根据是否实现PriorityOrdered接口、是否实现Ordered接口等确定调用顺序。
  另外还需要注意的是,在AbstractApplicationContext的invokeBeanFactoryPostProcessors方法中,会先从ApplicationContext中获取已有的BeanFactoryPostProcessor(当然也包括BeanDefinitionRegistryPostProcessor)列表,然后在后续的逻辑中,会先调用这些后置处理器,然后再调用从BeanFactory中获取的后置处理器。这些直接从ApplicationContext中获取的后置处理器是通过addBeanFactoryPostProcessor方法直接添加到容器中的,在Spring的环境下这是空的,但是在SpringBoot的环境中,在容器刷新之前会添加,这个在分析SpringBoot源码的时候再细说。所以说这两个后置处理器的来源有两个,一个是context本身,一个是BeanFactory,他们的调用顺序都是这样的:

  1. [from context]调用从context获取BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,这里没有进行排序,而是按照传入list的顺序调用
  2. [from beanFactory]调用实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,如果有多个实现了该接口的处理器,那么根据getOrder的返回值排序
  3. [from beanFactory]调用实现了Ordered接口的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,如果有多个实现了该接口的处理器,那么根据getOrder的返回值排序
  4. [from beanFactory]调用没有实现上述两个接口的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,如果有多个处理器,那么顺序得不到保证
  5. [from beanFactory]调用从context获取的BeanDefinitionRegistryPostProcessorpostProcessBeanFactory方法(因为BeanDefinitionRegistryPostProcessor也继承了BeanFactoryPostProcessor)
  6. [from context]调用从context获取BeanFactoryPostProcessor的postProcessBeanFactory方法,按照传入list的顺序调用
  7. [from beanFactory]调用实现了PriorityOrdered接口的BeanFactoryPostProcessor的postProcessBeanFactory方法,如果有多个实现了该接口的处理器,那么根据getOrder的返回值排序
  8. [from beanFactory]调用实现了Ordered接口的BeanFactoryPostProcessor的postProcessBeanFactory方法,如果有多个实现了该接口的处理器,那么根据getOrder的返回值排序
  9. [from beanFactory]调用没有实现上述两个接口的BeanFactoryPostProcessor的postProcessBeanFactory方法,如果有多个处理器,那么顺序得不到保证

注:在该方法的逻辑中,实现了BeanDefinitionRegistry接口的BeanFactory和没有实现该接口的BeanFactory调用逻辑不一样,如果BeanFactory没有实现BeanDefinitionRegistry,那么就不会有BeanDefinitionRegistryPostProcessor的调用,不过我们使用的都是DefaultListableBeanFactory,所以不考虑没有实现BeanDefinitionRegistry的情况

以上是关于Spring源码分析系列-Bean的生命周期(总结篇)的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码分析系列-Bean的生命周期(总结篇)

Spring源码分析系列-Bean的生命周期(总结篇)

Spring源码分析系列-Bean的生命周期(总结篇)

spring源码分析系列5:ApplicationContext的初始化与Bean生命周期

Spring系列使用InitializingBean和DisposableBean来管理bean的生命周期

Spring源码--Bean的管理总结