SpringBean作用域声明周期学习总结

最近在B站看了关于Spring的视频 , 下面是对SpringBean的一些知识做一个简单的总结

关于SpringBean面试中问的最多的问题

  1. 什么SpringBean
  2. SpringBean的作用域
  3. SpringBean的生命周期
  4. Spring是怎样解决循环依赖的(Spring容器的一级缓存/二级缓存/三级缓存)

什么是SpringBean

  • 视频中讲课老师提到SpringBean就是走过完整的SpringBean生命周期的Java对象 , 这句话没有官方支持但是个人感觉说的很对
  • 一个SpringBean肯定是一个Java对象 , 但一个Java对象不一定是一个SpringBean
  • SpringBean是由IOC容器来进行管理的
  • SpringBean是由用户提供给容器的配置元数据创建的

SpringBean的作用域

  1. 单例模式(singleton) , 该模式为默认 , SpringIoc容器只会存在一个共享的Bean实例 , 不管有多少个Bean引用它 , 都是同一个Bean @Scope(“singleton”)调整为单例模式
  2. 原型模式(prototype) , 每次从SpringIoc容器中获取一个Bean时 , 容器都会新建一个实例 , 每个Bean实例都有自己的属性和状态 , 无状态的Bean采用单例模式 , 有状态的Bean使用原型模式 , @Scope(“prototype”)调整为原型模式
  3. 同一请求(request) , 该模式针对用一Http请求 , 不同的Http请求会产生不用的实例 , 该Bean只针对当前Http Request内请求有效 , 当该次请求结束时该Bean也会被销毁 , @Scope(“request”)调整为同一请求模式
  4. 同一session(session) , 该模式下针对每个HttpSession产生一个新的实例 ,该实例仅针在该session中有效 , 不同的session会创建不同的实例 , @Scope(“request”)调整为同一请求模式
  5. 全局Session(global session) , 在一个全局的Http Session中,容器会返回该Bean的同一个实例,仅在使用portlet context时有效。这个只在其他文章中读到过 , 还没有运用过 , 希望大佬给补充一下

SpringBean的生命周期

简单来说生命周期分为4步 , 第一步是初始化 , 第二步属性赋值 , 第三步使用 , 第四步销毁 , 但这么讲根本没有把SpringBean中的核心知识讲出来 , 下面我就总结一下SpringBean的一个实例化过程

  1. 首先Spring容器启动的时候会做一个简单的扫描 , 看下那些类是需要我们Spring来进行管理的 , 将所有需要Spring管理的类解析为BeanDefinition , BeanDefinition中会存储关于一个Class的很多信息 , 比如class属性存的是类的全限定名 , abstract是否为抽象类 , lazy-init该类是否为懒加载等等的一些属性 , 最后将BeanDefinition存在BeanDefinitionMap中
  2. 扫描完成后会对BeanDefinitionMap做一个遍历 , 遍历中会对每一个BeanDefinition做一个判断 , 判断该类是否是懒加载 , 是否为单例 , 是否为原型 , 是否有DepensOn , 是否抽象 , 是否factory-bean等等一系列的验证
  3. 如果没有被提前暴露Spring则开始创建一个Bean , Spring会推断使用那个构造方法来创建一个Bean , 不用的模型会有不同的构造方法 , 找到对应的构造方法后会使用反射去实例化一个Java对象
  4. 实例化之后会判断当前是否支持循环依赖 , 如果支持循环依赖会将当前的Java对象所对应的ObjectFactory工厂类提前暴露出来 , 即存在二级缓存当中 , 二级缓存是一个Map
  5. 暴露完成之后会做一个属性填充就是属性注入
  6. 属性注入之后会去回调Awre接口和生命周期的回调方法
  7. 如果这个Bean有实现AOP则完成AOP的代理
  8. 最后将这个对象存在到单例池中 , 即一级缓存也就是Spring容器中

完整的流程图如下:
在这里插入图片描述

其中从推断构造方法开始到最后存入Spring容器中是一个SpringBean , 再加上第四步和第五步的使用和销毁 , 就是我个人理解的SpringBean的声明周期

Spring是怎么解决循环依赖的

首先说一下什么是循环依赖 , 个人理解就是一个A类有一个属性B类 , B类中有一个属性为 A类 , 当我们初始化A类的时候会需要注入B类就会去初始化B类 , 可B类也需要A类作为属性依赖 , 这就变成了一个死循环的过程 , 这个就是循环依赖 , Spring是默认支持循环依赖的 , 下面我们简单总结一下Spring是怎么解决循环依赖的

在上面的生命周期过程中 , 循环依赖发生在属性注入过程中 , 我们从属性注入开始总结

  1. 当A类走到属性注入的是时候发现需要一个B类 , 他回去在单例池中获取这个B类 , 显然是获取不到的 ,
  2. 此时会去三级缓存当中获取B类 , 此时是获取不到的
  3. 在三级缓存中没有获取到会去二级缓存中获取B类有没有被提前暴露在二级缓存当中 , 此时也是获取不到的
  4. 然后就会去执行B类的一个初始化过程
  5. 当B类走到了属性输入的时候发现需要一个A类作为属性的值取注入到属性当中
  6. 此时也会先去单例池当中获取A类 , 因为A类还没有走完完整的初始化过程 , 此时A类在单例池中也是获取不到的
  7. 获取不到之后会判断当前是否支持循环依赖 , 支持的话会去三级缓存当中获取 , 此时三级缓存也是获取不到的
  8. 获取不到后会去二级缓存当中查询是否有这个A类的ObjectFactory工厂类
  9. 这时我们在二级缓存当中会找到A类的ObjectFactory类
  10. 找到这个ObjectFactory类之后会使用这个ObjectFactory类去实例化一个对象作为临时使用的对象
  11. 此时就会产生一个A类 , 就可以将B类的属性注入 , 注入之后这个临时的A类会存在Spring的三级缓存当中
    10.这样B类就完成了初始化 , A类属性注入完成了

Spring是使用了一个二级缓存和三级缓存解决了循环依赖的问题的

笔者遇到的坑 : 常见的属性的自动装配是在属性值上加@Autowired注解完成 , 也可以定义一个属性 , 并在构造方法上添加@Autowired注解完成自动装配 , 在构造方法上添加@Autowired注解的方式是不支持循环依赖的

有兴趣的大佬们可以把Spring源码下载下来Debug研究一下 , 此次学习总结就这些 , 有什么写的不对的地方还希望大家指出来

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值