• Spring中循环依赖问题以及解决方案


    什么是循环依赖

    circular reference

    @Component
    public class A{
    	@Autowired
    	private B b;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    @Component
    public class B{
    	@Autowired
    	private A a;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    循环依赖其实就是循环引用,创建A的过程需要B,创建B的过程需要A,这样就会产生循环依赖问题。

    创建一个Spring bean过程如下:
    1.通过构造方法对A进行实例化(创建了一个普通对象,是一个半成品)
    2.填充A的属性
    3.进行初始化
    4.AOP(创建一个代理对象)
    5.将代理对象放到单例池(此时bean是全成品)

    第二步可能会产生循环依赖。

    Spring如何解决单例的循环依赖

    通过三级缓存来解决

    DefaultSingletonBeanRegistry:

        @Nullable
        protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        //1.Spring首先从一级缓存singletonObject中获取
            Object singletonObject = this.singletonObjects.get(beanName);
            //2.如果获得不到 并且显示对象正在创建
            if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
                Map var4 = this.singletonObjects;
                synchronized(this.singletonObjects) {
                //2.(1)就从二级缓存earlySingletonObjects中获取
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    //3.如果二级缓存中没有并且允许从singletonFactories中通过getObject拿到对象
                    //allowEarlyReference表示是否允许从singletonFactories中通过getObject拿到对象
                    if (singletonObject == null && allowEarlyReference) { 
                    //3.(1)从三级缓存中获取
                        ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                       //4.从三级缓存中获得到了对象之后
                        if (singletonFactory != null) {
                            singletonObject = singletonFactory.getObject();
                            //4.(1)把这个对象加入二级缓存earlySingletonObjects中
                            this.earlySingletonObjects.put(beanName,singletonObject);
                            //4.(2)并且从三级缓存中移除
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
    // 		返回这个对象
            return singletonObject;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在这里插入图片描述

    哪些循环依赖Spring无法处理

    1.构造器的循环依赖无法解决:
    构造器的循环依赖是:A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象。
    因为加入三级缓存的前提是通过执行构造器生成了普通对象,所以如果是构造器的循环依赖无法解决。
    2.Spring不支持prototype类型的bean属性循环依赖:
    它会在创建spring容器context时报错,因为对于原型bean,spring容器只有在需要时才会实例化,初始化它.
    3.@Async增强的bean的循环依赖无法处理

  • 相关阅读:
    redis集群中节点fail,noaddr
    痞子衡嵌入式:IAR环境下无法直接下载调试i.MXRT分散链接工程的解决方案(宏文件.mac+双Flashloader)
    一键安装|卸载 mysql 8.2.0 shell脚本
    Liunx文件操作命令(touch、cat、vim、more、less、cp、mv、rm、head、tail、file、find)
    深入linux内核架构--内存管理
    【Leetcode】2100. Find Good Days to Rob the Bank
    01背包问题
    MyBatis学习:使用占位符#
    linux常用基本命令
    2023蓝海赛道小说推文和短剧推广的授权方式
  • 原文地址:https://blog.csdn.net/qq_45968950/article/details/127673925