spring中bean循环依赖有哪些?spring都是怎么解决的?

循环依赖

A依赖B,B又依赖A,导致循环嵌套。
Spring中一共又三种循环依赖的现象。
1.构造器中的循环依赖。直接报错
2.单例scope下setter方法的循环依赖。使用三级缓存解决
3.非单例scope的循环依赖。不解决,由用户处理。

spring具体是如何处理的?

1.构造器中的循环依赖。

spring中存在一个正在创建对象的池子,创建对象时添加到该池子,this .singletonsCurrentlylnCreation.add(beanName)。创建完成从池子删除。试图创建某对象时,这样当创建前池中如果已经包含该对象名,直接返回BeanCurrentlylnCreationException 异常表示循环依赖。

2.单例scope时的setter方法循环依赖。

首先spring单例对象的初始化大略分为三步:

createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象
populateBean:填充属性,这一步主要是多bean的依赖属性进行填充
initializeBean:调用spring xml中的init 方法。

spring 对单例scope下引入了三级缓存。如下

/** Cache of singleton objects: bean name –> bean instance */
//一级缓存,存放初始化完成的对象
private final Map singletonObjects = new ConcurrentHashMap(256);
//二级缓存,存放已经实例化但未完成初始化的对象
/** Cache of early singleton objects: bean name –> bean instance */
private final Map earlySingletonObjects = new HashMap(16);
//三级缓存,存放进入实例化阶段的对象
/** Cache of singleton factories: bean name –> ObjectFactory */
private final Map> singletonFactories = new HashMap>(16);

getSingleton源码

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    //isSingletonCurrentlyInCreation()判断当前单例bean是否正在创建中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        //到这步说明一级缓存中不存在,且对象正在创建中,准备从二级缓存获取
        //加锁,防止多个线程同时进入,导致某线程从二级三级缓存中获取都为null 引发错误
        synchronized (this.singletonObjects) {
        //从二级缓存获取
            singletonObject = this.earlySingletonObjects.get(beanName);
            //从二级获取不到,且允许从三级缓存获取
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                //从三级缓存中获取到对象
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    //从singletonFactories中移除,并放入earlySingletonObjects中。
                    //其实也就是从三级缓存移动到了二级缓存
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

总体流程:

1.先从一级缓存中获取
2.获取不到且对象正在创建,则加锁从二级缓存获取(注意加锁,因为二级和三级缓存都是hashmap 非线程安全)。
3.如果从二级缓存中获取不到,且允许从三级缓存中获取。
4.从三级缓存中获取正在实例化的对象,并转移至二级缓存。
5.返回该对象

三级缓存中的对象,是在createBeanInstance实例化完成后,populateBean填充属性前放入的。
这也说明了为什么构造器中的循环依赖无法解决,因为三级缓存要在实例化完成后才放入呀。

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);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
}

那么循环依赖的事情就清楚了:

实例化A后,将A放入三级缓存singletonFactory,填充属性时发现引用了对象B,则实例化B,将B也放入三级缓存,填充属性是发现依赖A,通过一级缓存二级缓存都没有找到A,最终通过三级缓存获取到A,B完成初始化。A完成属性填充及初始化,放入一级缓存。
从而避免了循环依赖的问题。

用来两级缓存可以吗?

一级缓存:存储单例bean,即 Map<String, Object> singletonObjects( bean name to
bean instance. )
二级缓存:存储提前暴露的bean,真正的解决循环依赖是靠二级缓存的。Map<String, Object>earlySingletonObjects (Cache of early singleton objects: bean name to bean instance.)
三级缓存:存储bean和其要加强的aop处理,如果需要aop增强的bean遇到了循环依赖,则使用该缓存中的aop处理代理增强bean(Cache of singleton factories: bean name to ObjectFactory.)

实际上不用三级缓存也可以解决循环依赖,但是如果有需要aop增强的bean时,就要在初始化bean的时候对bean做增强了,这违背了Spring在结合AOP跟Bean的生命周期的设计!
Spring结合AOP跟Bean的生命周期本身就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来完成的,在这个后置处理的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理。如果出现了循环依赖,那没有办法,只有给Bean先创建代理,但是没有出现循环依赖的情况下,设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化后就立马完成代理。

最后一种prototype 作用域下的循环依赖

对于prototype作用域的下的bean,spring的原则是只负责简单的创建,其他的事情交由使用者负责,所以循环依赖只有考用户自己解决了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值