前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring技术知识点总结之一——循环依赖

Spring技术知识点总结之一——循环依赖

作者头像
剑影啸清寒
发布2020-07-10 11:18:52
4210
发布2020-07-10 11:18:52
举报
文章被收录于专栏:琦小虾的Binary琦小虾的Binary

一. Spring IOC 循环依赖?

参考地址: 《Spring IOC 容器源码分析 - 循环依赖的解决办法》 《Spring IOC循环依赖解决方案分析》 《Spring5源码阅读--如何解决循环依赖?》

在 Spring 中获取一个 Bean,是通过获取 BeanDefinition 实现的:在定义 Bean 信息的 XML 文件中,BeanDefinitionReader 读取指定路径下的 XML 文件,获取 Bean 定义信息并封装成 BeanDefinition 对象,该实例对象包含依赖关系信息 dependsOn。通常依赖关系是在 XML 的 p:xxx-ref,或者通过类的 @Autowired 等手段实现的。

循环依赖,就是在 classA 和 classB 的属性中,都互相包含彼此。Spring 避免循环依赖出现的错误,使用了三层缓存:

  • 单例缓存 singletonObjects:存放填充完毕的,实际的 BeanDefinition
  • Bean 定义缓存 earlySingletonObjects:存放未填充的 BeanDeinition (属性值全为 null),用于解决循环依赖问题;
  • 工厂缓存 singletonFactories:存放单例 Bean 的工厂对象,在循环依赖问题中用来辅助解决问题;
    • singletonFactories 的 key 为 beanName,value 为该 bean 对应的 bean 工厂;这样一个 bean 就可以通过 beanName 从对应的 bean 工厂中找到对应的 bean。

分析 getSingleton() 方法:

代码语言:javascript
复制
public Object getSingleton(String beanName){
    //参数true设置标识允许早期依赖
    return getSingleton(beanName,true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //检查缓存中是否存在实例
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        //如果为空,则锁定全局变量并进行处理。
        synchronized (this.singletonObjects) {
            //如果此bean正在加载,则不处理
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {  
                //当某些方法需要提前初始化的时候则会调用addSingleFactory 方法将对应的ObjectFactory初始化策略存储在singletonFactories
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    //调用预先设定的getObject方法
                    singletonObject = singletonFactory.getObject();
                    //记录在缓存中,earlysingletonObjects和singletonFactories互斥
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

依旧以 classA 和 classB 为例,假设两个实例对象存在循环依赖关系,且 classA 对象首先在 Spring 容器中初始化。

  1. 构建 classA 对象的未填充 BeanDefinition 对象,并置入 earlySingletonObjects,同时**将该 bean 从工厂缓存 singletonFactories 中除掉**,为解决循环依赖做准备;
  2. 尝试向 classA 对象中填充内容,且填充过程到需要填充 classB 对象;
  3. 首先分别尝试从完全实例化完毕的单例缓存 singletonObjects 和不完全实例化的 earlySingletonObjects 中获取 classB 对象,都获取失败;
  4. 尝试初始化 classB 对象的 BeanDefinition。在初始化过程中,classB 对象需要引用到 classA 对象实例,此时出现了循环依赖的情况;
  5. classB 对象尝试从 singletonObjects 中获取 classA,但获取失败(因为此时 classA 当前还在初始化过程中,所以没有放入 singletonObjects 中);然后从 earlySingletonObjects 中获取 classA 的引用
  6. classB 获取到 classA 的引用后,可以继续完成实例化过程;
  7. classB 实例化完成后,实例对象返回给 classA,然后 classA 完成其实例化过程。

至此,循环依赖的 classA 和 classB 都完成了实例化。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-07-09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一. Spring IOC 循环依赖?
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档