Day 6 Bean 的生命周期

建议浏览顺序从Day 1 开始

1 Bean的声明周期

Spring Bean的生命周期是从 Bean 实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象最终存储到单例池中,这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段:

  • Bean 实例化阶段:Spring 框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是Singleton的是否是延迟加载的,是否是FactoryBean,最终将一个普通改的singleton的Bean通过反射进行实例化。总结来说就是对BeanDeifinition进行解析,然后实例化对象

  • Bean的初始化阶段:Bean创建之后仅仅是一个"半成品",还需要对Bean的实例的熟悉进行填充,执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法。该阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,后面要学习的Spring的注解功能等spring高频面试题Bean的循环引用问题都是在这个阶段体现的;

总结来说就是:在实例化后,通过执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法(相当于初始化方法),对bean进行填充。

  • Bean的完成阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期。

Spring Bean的初始化过程涉及如下几个过程

  • Bean实例的属性填充,在xml标签配置

  • Aware接口属性注入,实现接口

  • BeanPostProcessor的before()方法回调, 后处理器

  • InitializingBean接口的初始化方法回调,实现接口

  • 自定义初始化方法init回调,自定义然后通过xml配置

  • BeanPostProcessor的after()方法回调,后处理器

PS:通过代码验证上述初始化顺序.......

Spring在进行属性注入时,会分为如下几种情况:

  • 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去

  • 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;

  • 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题,下面会详细阐述解决方案

重点在于双向注入循环引用问题:

  • UserService里面有set方法放入UserDao

  • UserDao里面有set方法放入UserService

重点可以打断最后的红线,将UserService的半成品存入map,UserDao先找SingletonObjects,没有找到然后找map(多级缓存)。

解决方案:

Spring提供了三级缓存存储完整Bean实例和半成品Bean实例,用于解决循环引用问题

DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:


    /** Cache of singleton objects: bean name to bean instance. */
    // 1. 一级缓存,最终存储单例Bean成品容器,即实例化和初始化完成的Bean
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    // 2. 二级缓存,存储单例Bean半成品容器,且当前对象已经被其他对象引用了
    /** Cache of singleton factories: bean name to ObjectFactory. */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    //3.  三级缓存,单例Bean的工厂池,存储半成品,对象未被引用,使用时通过工厂创建Bean
    /** Cache of early singleton objects: bean name to bean instance. */
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

UserService和UserDao循环依赖的过程结合上述三级缓存描述一下

  • UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存;

  • UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao;

  • UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存

  • UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移入二级缓存;

  • UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存

  • UserService 注入UserDao;

  • UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存

Spring IoC 整体流程总结

从读取xml-> beanDefinition->beanDefinitionMap->bean实例化->bean初始化->进入SingletonObjects中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兜兜转转m

一毛钱助力博主实现愿望

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值