spring循环依赖

Spring循环依赖的三种方式

依赖场景:A->B->A 或者 A->B->C->A

1.理解spring循环依赖的原理,首先了解一下Spring bean在容器中创建到销毁的若干阶段。

单例bean循环依赖体现在实例化和填充属性两个阶段,对应构造器和set方式(Singleton、Prototype)循环依赖。

2.Spring解决循环依赖主要使用了其三级缓存:

// singletonObjects 主要缓存初始化完成的单例对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

// earlySingletonObjects用户缓存提前暴露的单例对象的Cache,只进行实例化未初始化完成
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

// singletonFactories 单例对象工厂的缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

3.获取单例bean的方法

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

isSingletonCurrentlyInCreation()判断当前单例bean是否正在创建中,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象, 或者在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。
allowEarlyReference 是否允许从singletonFactories中通过getObject拿到对象

// 如果设置了单例bean提前暴露,会调用addSingletonFactory方法。
boolean earlySingletonExposure = (mbd.isSingleton() 
            && this.allowCircularReferences 
            && isSingletonCurrentlyInCreation(beanName));


    addSingletonFactory(beanName, new ObjectFactory() {
        public Object getObject () throws BeansException {
            return getEarlyBeanReference(beanName, mbd, bean);
        }
    });

// 此处getEarlyBeanReference通过SmartInstantiationAwareBeanPostProcessor执行无参构造方法创建对象。

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);
        }
    }
}

Spring不能解决构造方法的循环依赖,能解决set方式(singleton)依赖。prototype作用域bean,不论set和构造器方式,Spring容器无法完成依赖注入,因为Spring容器不进行缓存"prototype"作用域的bean,因此无法提前暴露一个创建中的bean。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值