循环依赖-浅谈Spring Circle Reference

Spring是如何解决循环依赖的:createBeanInstance --> addSingletonFactory
–>getSingleton

  1. Spring三级缓存
    singletonObjects:单例池 存放经过了完整的生命周期的bean
    earlySingletonObjects:提前暴露出来的bean缓存 存放完成实例化 或者 完成aop的代理对象的bean
    singletonFactories:缓存的是一个ObjectFactory,value存放的是一个函数,走wrapIfNecessary走是否需要AOP的逻辑 完成后 放到earlySingletonObjects缓存 同时这个缓存remove掉这个元素

  2. 看了Spring涉及的三级缓存,我们就能理解出开发者是怎样利用缓存解决循环依赖的问题了,主要就是两个地方的实例,一是生命周期中的实例化阶段,二是生命周期的初始化后的AOP的阶段

  3. 接下来举例:

@Component
Class A {
	@Autowired
	private B b;
}

Class B {
	@Autowired
	private A a;
}
  1. A开始doCreateBean
if (instanceWrapper == null) {
	// 走生命周期中的实例化 返回类型为BeanWrapper getWrappedInstance方法就会返回该bean的实例化的bean
	instanceWrapper = createBeanInstance(beanName, mbd, args);
}

// 之后进三级缓存
// 三个条件 单例,allowCircularReferences=true,A正在创建
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
	if (logger.isTraceEnabled()) {
		logger.trace("Eagerly caching bean '" + beanName +
				"' to allow for resolving potential circular references");
	}
	// 添加到三级缓存 vale传入了一个函数 getEarlyBeanReference中wrapIfNecessary走AOP
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
  1. 开始注入B,先会去找doGetBean中getSingleton方法,缓存中没有找到B的bean。
    然后开始进行B的doCreateBean方法,B开始实例,属性注入,注入到A时候doGetBean下面这个方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Quick check for existing instance without full singleton lock
    // 先从单例池找 如果找不到 并且发现要找的这个bean正在创建中...
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    	// 二级缓存找
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
            synchronized (this.singletonObjects) {
                // Consistent creation of early reference within full singleton lock
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) {
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                        	// 从三级缓存 取数据 getObject 执行之前lambda表达式函数 添加到二级缓存 三级缓存remove该元素
                            singletonObject = singletonFactory.getObject();
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
        }
    }
    return singletonObject;
}
  1. 这样就可以拿到A的实例(原始对象)或者A的AOP实例(代理对象),进行注入完成B类的bean完整生命周期,A类也可以完成B的注入。

  2. 在wrapIfNecessary方法 会判断是否完成类AOP代理 如果提前完成了代理 不会再次代理,保证注入的与生成的bean是一个对象。

  3. 总结
    Spring的循环依赖,只能解决没有进行特殊后置处理器的return bean(简单的bean和aop)。如果在后置处理器直接return一个新的类出来,这里就会有问题了,可以修改allowCircularReferences=false,自己控制循环依赖就可以了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值