spring如何解决循环依赖问题?

什么是循环依赖?

循环依赖就是两个或者多个bean之间相互依赖,形成依赖闭环. 例子: A对象包含属性B,B对象包含属性A,如下图:

spring在处理循环依赖的问题上采用了三级缓存 

三级缓存在bean创建的那个时机会用到?

1.bean实例化之前会查询缓存,判断bean是否已经存在

2.bean属性赋值之前会先向三级缓存中放入一个lambda表达式,该表达式执行则会生成一个半成品Bean放入二级缓存

3.Bean初始化完成后将完整的Bean放入一级缓存,同时清空二、三级缓存

bean创建的过程:

以上三个时机的源码分析 

1. bean实例化之前 

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        //从singletonObjects(一级缓存)中获取,获取不到继续往下走
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            //从earlySingletonObjects(二级缓存)中获取,获取不到继续往下走
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                //为了线程安全加锁
                synchronized(this.singletonObjects) {
                       //从一级缓存中获取,获取不到往下走
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        //从二级缓存中获取,获取不到往下走
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            //从三级缓存中获取lambada表达式
                            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
                                //根据lambada表达式获取bean
                                singletonObject = singletonFactory.getObject();
                                //将获取到的bean放入二级缓存中
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                //从三级缓存中移除
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }

        return singletonObject;
    }

整体逻辑总结为:

  1. 从一级缓存获取,获取到了,则返回
  2. 从二级缓存获取,获取到了,则返回
  3. 从三级缓存获取,获取到了,则执行三级缓存中的lambda表达式,将结果放入二级缓存,清除三级缓存

 2. bean属性赋值之前

AbstractAutowireCapableBeanFactory#doCreateBean

 

 addSingletonFactory

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized(this.singletonObjects) {
            //如果一级缓存中不存在的话,往下走
            if (!this.singletonObjects.containsKey(beanName)) {
                //放入三级缓存
                this.singletonFactories.put(beanName, singletonFactory);
                //删除二级缓存中对应的bean
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }

        }
    }

 AbstractAutowireCapableBeanFactory#getEarlyBeanReference

该方法逻辑:判断该Bean是否需要被动态代理

  • 不需要代理,返回未属性注入、未初始化的半成品Bean
  • 需要代理,返回未属性注入、未初始化的半成品Bean的代理对象

 

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
        Iterator var5 = this.getBeanPostProcessors().iterator();
        // 遍历后置处理器
        while(var5.hasNext()) {
            BeanPostProcessor bp = (BeanPostProcessor)var5.next();
            // 找到实现SmartInstantiationAwareBeanPostProcessor接口的
            // 该接口getEarlyBeanReference方法什么时候会执行?
            // AOP动态代理的时候 该方法执行就是判断该Bean是否需要被代理
            // 需要代理则会创建代理对象返回
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor)bp;
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
    }
    // 这个Object有两种情况,一是实例化后的半成品Bean,二是半成品Bean动态代理后的代理对象
    return exposedObject;
}

注意:这里只是把lambda表达式放入了三级缓存,如果不从三级缓存中获取,这个表达式是不执行的,一旦执行了,就会把半成品Bean或者半成品Bean的代理对象放入二级缓存中了

3. Bean初始化完成后

AbstractBeanFactor#doGetBean 

这里注意啊,这个getSingleton方法传参传了个lambda表达式,这个表达式内部就是Bean的实例化过程,初始化完成后,是要需要执行这个getSingleton方法的 

 

DefaultSingletonBeanRegistry.getSingleton(beanName, singletonFactory) 

这个方法与上面那个不一样,重载了 

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
     
        synchronized(this.singletonObjects) {
            // 第一次进来这里获取肯定为null
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               // 省略................
                try {
                    // 注意啊,这个就是执行外面那个传参的lambda表达式
                    // 所以这里才会跳到createBean方法那里去执行
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                } 
                // 省略................
                finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
                    this.afterSingletonCreation(beanName);
                }
                // 到了这说明Bean创建完了
                if (newSingleton) {
                    // 这里就会把Bean放入一级缓存中了 同时清除二、三级缓存
                    this.addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }

 DefaultSingletonBeanRegistry#addSingleton

protected void addSingleton(String beanName, Object singletonObject) {
  synchronized(this.singletonObjects) {
     // 放入一级缓存  
      this.singletonObjects.put(beanName, singletonObject);
      // 清除二、三级缓存
      this.singletonFactories.remove(beanName);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
  }
}

 总结:

整个过程就三个地方跟缓存有关,我们假设现在要实例化A这个Bean,看看缓存是怎么变化的:

实例化前,获取缓存判断(三个缓存中肯定没有A,获取为null,进入实例化流程)
实例化完成,属性注入前(往三级缓存中放入了一个lambda表达式,一、二级为null)
初始化完成(将A这个Bean放入一级缓存,清除二、三级缓存)

 

一级缓存,存放完整bean:

Map<String, Object> singletonObjects

二级缓存,存放半成品bean:

Map<String, Object> earlySingletonObjects

三级缓存,存放工厂对象(lambda表达式):

Map<String, ObjectFactory<?>> singletonFactories

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值