当前位置: 首页 > article >正文

Spring如何解决bean的循环依赖

(一)循环依赖 

   什么是循环依赖呢?简单来说就是在IOC中A在创建时候要先创建B,但是B在创建的时候又要先创建A,类似于死锁

(二)三级缓存

spring使用三级缓存来帮助我们解决了循环依赖的问题,首先我们来看一张图

这张图就能很好的概括了,spring底层源码是如何解决循环依赖的

  我们来跟着这个图走一下,首先我们会调用getBean方法,接着内部调用doGetBean()

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
    @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
  // 尝试通过bean名称获取目标bean对象,比如这里的A对象
  Object sharedInstance = getSingleton(beanName);

  // 我们这里的目标对象都是单例的
  if (mbd.isSingleton()) {
    // 这里就尝试创建目标对象,第二个参数传的就是一个ObjectFactory类型的对象,这里是使用Java8的lamada
    // 表达式书写的,只要上面的getSingleton()方法返回值为空,则会调用这里的getSingleton()方法来创建
    // 目标对象
    sharedInstance = getSingleton(beanName, () -> {
      try {
        // 尝试创建目标对象
        return createBean(beanName, mbd, args);
      } catch (BeansException ex) {
        throw ex;
      }
    });
  }
  return (T) bean;
}

  在doGetBean()的内部我们调用了getSingleton()方法   这个方法是用来获取我们一级缓存中的完整Bean的,此时我们一级缓存中并没有Bean所以获取失败,所以我们会调用第二个getSingleton()方法然后调用里面的createBean()创建一个Bean

  在createBean中首先我们要先经过一个实例化(加入到三级缓存中(缓存的是函数接口:通过lambda表达式 传入Bean的实例和Bean的名字(aop创建)但是不会立即调用))然后就到了属性赋值 发现我们依赖BeanB此时又会调用getBean(B)之后的步骤与创建BeanA是一样的,直到属性赋值,发现又依赖A

  此时调用getBean(A)然后doGetBean(A)然后调用getSingleton先去一级缓存找,我们发现还是找不到,然后就去二级缓存找也没有,再去三级缓存中找,我们发现三级缓存中是有的,此时我们会调用三级缓存(如果实现了aop就创建动态代理,如果没有就会返回Bean的实例)然后保存在二级缓存中

注: 那这里我们会问?为什么要放到二级缓存中?,目的是为了避免重复创建动态代理(a依赖b和c,b依赖a,c也依赖a就会重复创建)

 我们继续,此时我们A的动态代理创建好了,那么BeanB中的BeanA就有了,此时就可以返回了,然后BeanB就继续执行生命周期经过初始化然后再调用getSingleton方法,然后把BeanB就放到一级缓存中,并溢出二级缓存和三级缓存 然后返回

 此时BeanA得到BeanB之后,也可以继续走流程了,这样就解决了循环依赖的问题

(三)总结

这里我们来说一下每一级缓存是干什么的,以及一些问题

一级缓存:存储完整的Bean

二级缓存:避免多重循环依赖的情况,重复创建动态代理

三级缓存:

  三级缓存时函数式接口:通过lambda表达式把方法传入进去(把Bean的实例和Bean名字传入(aop创建))

  不会立即调:为什么不会立即调用呢?如果立即调用,那么所有的aop不管bean是否循环依赖都会在实例化后创建动态代理,但是正常情况下我们应该再初始化才创建动态代理,所以spring还是希望我们再正常时,在初始化阶段创建动态代理

 会在ABA第二次调用getBean(A)的时候才去调用三级缓存

 放入二级缓存(避免重复创建)

问: 二级缓存能不能解决循环依赖?

  如果只是解决死循环问题,那么我们一级缓存就可以了,我们只需要在实例化中创建动态代理放到一级缓存中,之后我们从一级缓存拿就可以(但是无法避免在并发下获取不完整的Bean)

 二级缓存也可以解决循环依赖,但是如果出现重复循环依赖,就会创建多次aop动态代理

问:Spring有没有解决多例Bean的循环依赖?

多例不会使用缓存进行存储(多例Bean每次使用都需要重新创建) 

不缓存早期对象就无法解决循环依赖


http://www.kler.cn/a/447281.html

相关文章:

  • 常用的JVM启动参数有哪些?
  • 前端导出PDF的组件及方法
  • HBase、Hive、Redis 和 MongoDB的对比
  • webGL硬核知识:图形渲染管渲染流程,各个阶段对应的API调用方式
  • fastdds:idl
  • 常用es命令
  • centos stream 8下载安装遇到的坑
  • 方正畅享全媒体新闻采编系统 reportCenter.do SQL注入漏洞复现
  • 天天 AI-241220:今日热点-OpenAI整大活!ChatGPT新增电话功能,全民AGI要来了
  • 软件项目开发中,需求分析所占比例一般是多少?
  • Java面试被问到GC相关问题如何回答?
  • 研发效能DevOps: Vite 使用 Element Plus
  • 使用docker拉取镜像很慢或者总是超时的问题
  • 字符串解析 Python Basic (工业设备通用语言)
  • Type-C 接口电热毯:开启温暖智能新时代
  • SQLite数据库的介绍和使用
  • 前端知识图谱 - JavaScript基础(变量和类型)
  • git怎么将一个没使用过git的项目上传到某个仓库
  • [计算机网络]唐僧的”通关文牒“NAT地址转换
  • Java写URI网址唤醒APP小程序等NDEF信息
  • IP地址查询的背后②:IP地址(IPv4)的构成、类型以及子网划分
  • vscode的keil assistant 中搜索不到全局变量
  • RTOS之邮箱
  • JAVA学习-练习试用Java实现“使用Arrays.sort方法对整数数组进行排序”
  • SQL进阶技巧:如何计算商品需求与到货队列表进出计划?
  • 深度学习之超分辨率算法——SRGAN