【spring源码解析】bean的一生

本文深入探讨了Spring框架中Bean的生命周期,包括工厂的创建、Bean的初始化、后置处理器的注册以及如何处理循环依赖问题。在Bean的创建过程中,详细阐述了从加载配置到创建Bean实例的每个步骤,特别是如何检测和解决循环依赖。文章强调了Spring的精妙设计,并鼓励读者深入研究以提升技术水平。
摘要由CSDN通过智能技术生成

探究源码

我们进入调试查看源码

由于源码非常之多,这里就只记录执行过程中做的一些事情

工厂源码

加载过程

新建对象找到spring对象的位置,找到配置文件的位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nXs6Lt16-1633886743882)(spring.assets/image-20211010200357454.png)]

之后判断refresh,开始刷新

refresh

spring最核心的方法,refresh都做了什么呢?

首先就是准备刷新:

  • 记录毫秒值,是不是关闭,选择启动
  • 日志打印,给子类做一些默认的事情,校验一些属性,有没有子类复写的一些属性,如果有就执行,没有继续往下走
  • 判断,之后将应用的一些初始化事件放到集合里

准备好刷新之后,

准备bean工厂

  • 添加bean的加载器,spring表达式的解析器,属性编辑器
  • 设置一些必要的后置处理器
  • 忽略一些接口
  • 将bean的信息注册,加入资源解析器,注册事件发布,上下文对象
  • 获取一些系统属性判断加载,如:jre的名字,user.home的路径,语言环境等等
  • 之后返回工厂对象

工厂对象创建

  • 判断是否有工厂,没有的话创建
  • 创建一个默认的工厂返回。默认创建的工厂包含了很多的默认信息
  • 之后给bean工厂按满足的条件赋值
  • 解析描述信息类,加载描述信息,如果是xml那么就是解析xml
  • 将解析完的类描述i信息,复制到Bean工厂里

到这里工厂的创建就完成了

后置处理器

注册全部的后置处理器,一般来说。有多少注入的类就有多少后置处理器

执行流程

  • 遍历,有多少后置处理器,创建集合,循环判断所有处理器,是否属于当前接口,之后将所有的后置处理器放在对应的集合里,给处理器id
    • 优先级
    • 内部的
    • 等等
  • 之后,给优先级集合中的处理器排序,有序的注册
  • 之后判断其他的处理器的集合
  • 最后判断没有优先级的集合,最终全部注册到容器中

国际化和事件监听器

  • 判断是否有国际化,如果包含,加入到工厂里,输出日志调用
  • 事件监听器也是,判断是否有,如果保函就从里面拿出来,日志输出,如果不保函就创建一个事件监听器,

注册事件监听器

  • 默认是没有,如果有,拿到全部的默认监听器
  • 设置临时类加载器
  • 判断事件监听器是否是空的,如果不是就全都拿来发出去,

创建bean

创建单例对象,不能是懒加载的

  • 首先先寻找工厂里有没有值解析器,如果没有就创建一个新的值解析器
  • 查看冻结配置,为true就将存放再配置文件的bean组件们,转换成字符串数组
  • 根据名字从集合中拿出来,遍历创建对象,根据名字拿到bean的信息,满足三个条件才往后走
    • 不能是抽象的
    • 必须是单例的
    • 不能是懒加载的
  • 如果不满足,那就是工厂创建
  • 从缓存拿到单例对象,要是没有就去看是否满足判断条件,查看是否多次创建对象,之后查看bean工厂,
  • 标记当前对象,正在创建,之后放到set集合中,表示最后一次创建,
  • 检查当前bean的信息,查看是否需要其他的依赖来创建,判断是不是单例,
  • 用集合存放对象和一个构造工厂
  • 有一个实例resolveBeforeInstantiation的创建,通过后置处理器,来实现创建代理对象,这一步就是有可能创建对象的,当我们要用aop的时候就用这个方法拿到代理对象.
  • 如果没有就创建对象,传入对象信息,再次判断是不是单例的,之后创建单例对象,
  • 之后判断对象,看是不是需要必须指定的构造方法,默认是空参数构造方法,
  • 之后拿到bean实例,判断是否为空,判断接口类型,检查对象,拿到无参数构造方法
  • 创建对象,用反射标记当前的构造方法,用无参构造方法构建实例,到这里bean对象就创建成功了
  • 这里的bean对象是最初始的状态,包装给BeanWapper做一个初始化,到这里空的对象就创建好了。
  • 之后调用后置处理器,回调如果组件里有就调后置处理器,最后到了这里开始对空对象赋值
  • 之后再次拿到单例对象,之后就去拿到赋值,返回创建的对象
  • 通过单例工厂创建出对象,将新建的对象放入单例对象集合中
  • 移除用来检查循环依赖的单例工厂,确认注册对象成功,set的不会存放重复值的,所以就一个
  • 经过大量判断之后返回对象实例

完成刷新,发布事件消息

  • 初始化包含的处理器,如果有就get拿进去,如果没有那就创建
  • 之后刷新后置处理器
  • 发送创建事件信息,告诉spring初始化完成了
  • 之后注册上下文拿到当前的名字。如果不等于空那就加入到applicationContext中,至此完成

循环依赖问题

我们创建两个对象,

UserA的构造方法调用UserB对象

循环依赖,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ktL8AImX-1633886743883)(spring.assets/image-20211011010440079.png)]

这个是调试断点进入到有参构造方法

  • 进入之后,可以看到需要参数要引用到UserB,UserB也是个bean所以spring要去创建userB所以userB就需要参数创建userA导致一直循环创建
  • 当spring发现UserB还在创建userA的时候spring就会抛出异常为什么再次创建的时候就异常了呢?
  • 因为存放获取bean的是set之前创建bean的时候我们有提到,只要创建bean就会放在里,有个判断,set是没有重复值的只要判断没通过,就证明之前有正在创建的对象·,于是抛出异常
  • 通过缓存的要创建的bean来判断是否重复引用bean,解决循环依赖问题

如何解决呢?

  • 我们用构造方法调用引用其他类,创建的时候,一直在重复的创建对象
  • 我们只需要,用属性来声明一个应用对象,需要的时候调用,使用的完就销毁
  • 就不会存在循环依赖的问题了

总结

spring框架的精妙之处,太多值得我们学习,这次的bean的一生只是将思想和大致过程讲解,还有很多需要结合场景的细节,需要我们自己的去探索,不断地深究才可以让自己的技术变得强大

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

冷环渊

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值