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的生命周期(总结篇)相关推荐

  1. Spring源码分析系列——bean创建过程分析(三)——工厂方法创建bean

    前言 spring创建bean的方式 测试代码准备 createBeanInstance()方法分析 instantiateUsingFactoryMethod()方法分析 总结 spring创建be ...

  2. 【Spring源码】讲讲Bean的生命周期

    1.前言 面试官:"看过Spring源码吧,简单说说Spring中Bean的生命周期" 大神仙:"基本生命周期会经历实例化 -> 属性赋值 -> 初始化 -& ...

  3. 小米面试官:说说Spring源码里面的Bean的生命周期!

    1. Bean的实例化概述 前一篇分析了BeanDefinition的封装过程,最终将beanName与BeanDefinition以一对一映射关系放到beanDefinitionMap容器中,这一篇 ...

  4. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

  5. 【Spring源码分析】Bean加载流程概览

    代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...

  6. beaninfo详解源码解析 java_【Spring源码分析】Bean加载流程概览

    代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...

  7. spring源码分析系列(一)

    本系列以官方开发文档+spring5的源码为主 一.IOC 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.其中 ...

  8. Spring源码分析:Bean加载流程概览及配置文件读取

    很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已 ...

  9. 【Spring源码分析系列】bean的加载

    前言 以 BeanFactory bf  = new XmlBeanFactory(new ClassPathResource("beans.xml"));为例查看bean的加载过 ...

最新文章

  1. 分析动态代理给Spring事务埋下的坑
  2. Java编程操作Excel的一种方法
  3. 对我国域名系统安全问题的思考
  4. C/C++常见报错问题描述及解决方案
  5. 学电脑从新手到高手_小白如何学手绘插画?新手到高手必学的四套教程【614期】...
  6. 理解“动心忍性”的含义
  7. android 非root app 捕捉系统广播_APP的生死之道
  8. 网络编程知识预备(5) ——libcurl库简介及其编程访问百度首页
  9. 怎样呵护友谊_呵护友谊需要学会尊重对方.PPT
  10. acm杭州电子科技大学新生赛
  11. 目前主流的数据库有哪些?
  12. 4.2 录制第一个jmeter性能测试脚本(http协议)
  13. c语言求利用麦克劳林公式求sinx值,用泰勒公式求sin(x)的近似值
  14. NYOJ:71-独木舟上的旅行
  15. 小程序使用本地图片报错问题 Failed to load local image resource
  16. vimium 成神之路-键盘党的胜利
  17. Vue3使用Swiper
  18. rangeOfString 失效了
  19. Linux-基本使用
  20. 思科华为常见的万兆光模块型号大全

热门文章

  1. 推荐系统实践 - 第2章
  2. mysql explain extended_MySQL EXPLAIN extended
  3. 王者荣耀1v1单挑,柜台商品管理系统
  4. sublime插件配置说明文档
  5. CSS 布局 - position 属性:绝对定位和相对定位
  6. PPT基础入门实例:倾斜型封面页制作
  7. 自己开发了一个财神小童子合成
  8. 润达软件财神节聚餐晚会
  9. impala 时间日期函数全解
  10. linux 挂载SD卡和扩展虚拟内存