剑指spring源码(五)---循环依赖

剑指spring源码(五)—循环依赖

循环依赖问题是一个非常热门,非常有意思的话题,每次想到这个问题都会很高兴,第一次接触循环引用还是看java虚拟机的时候,如何判断一个对象已死?计数器法虽简单但却存在ABA问题,采用可达性分析算法才算解决了这个问题。如今学习spring又碰到了类似的问题,怎能不高兴

spring的循环依赖是什么

假设有A,B两个类,A类有B属性,B类有A属性,那么当spring扫描到这两个类,如何对这两个类进行实例化

public class A{
	B b;
}
public class B{
	A a;
}

如上面代码,我先实例化A对象,然后给A注入属性B,但是他发现此时B还没有被实例化,于是去实例化B,然后给B注入属性A,但是此时A还不是一个完整的A,即A不在单例池中,如果不采取措施,他们两个将无限循环下去。如何解决呢?
想要解决循环依赖,必须先发现这个问题,我们可以用一个singletonsCurrentlyInCreation集合存储当前正在创建的bean,什么叫正在创建的bean,即暂时没有被加到单例池的,如果再getBean时刻他发现singletonsCurrentlyInCreation有自己了,那么此时肯定是循环依赖了,那么如何解决呢?不考虑aop的情况下,我们可以定义一个earlySingletonObjects 早期单例池存储没有进行DI的bean。基于上面的假设,我们再来模拟ABA问题

还是先实例化A,把A加入到singletonsCurrentlyInCreation,earlySingletonObjects 中,给A注入属性B,实例化B,把B加入到singletonsCurrentlyInCreation,earlySingletonObjects,给B注入属性A,此时再去getBean(A.class),他就会发现singletonsCurrentlyInCreation已经有自己了,所以断定此时发生循环依赖,但是他会去earlySingletonObjects 把A取出来给B注入,此时B就完成了,加入singletonObjects(单例池),A再回过头来把B注入即可。 可能有人会说,不对啊,B类注入了一个没有DI的A对象,其实这没有关系的,就像引用传递一样,传一个对象到另一个函数
其实上面这些思路在没有aop的情况下是完全正确的,并且经得起考证,因为本人手写ioc就是这个逻辑,并且正确解决了循环依赖,有aop的情况会涉及到另一个很复杂的东西,singletonFactories, 这个我把它理解为aop单例工厂,它可以调用后置处理器产生aop代理对象

spring循环依赖图示

在这里插入图片描述

spring循环依赖代码分析

对应图示getSingleton(beanName);

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//单例池中拿 第一级缓存
		Object singletonObject = this.singletonObjects.get(beanName);
		//单例池没有
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			//锁住单例池
			synchronized (this.singletonObjects) {
				//early中拿 第三级缓存
				singletonObject = this.earlySingletonObjects.get(beanName);
				//第三级缓存拿不到
				if (singletonObject == null && allowEarlyReference) {
					//singletonFactories拿 ,第二级缓存 object工厂生产代理加工代理对对象
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						//第二级缓存拿到了
						singletonObject = singletonFactory.getObject();
						//put到三级缓存,为了高效,singletonFactory.getObject()这一步耗时
						this.earlySingletonObjects.put(beanName, singletonObject);
						//移除二级缓存
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

对应图示提前暴露工厂

		//单例&&true(默认支持循环依赖)&& 此bean正在创建
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			//添加到单例池  提前暴露工厂
			//第四次后置处理器
			//SmartInstantiationAwareBeanPostProcessor---getEarlyBeanReference
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
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);
			}
		}
	}

对于aop代理,普通的是在倒数第二步进行代理的,但是循环引用情况下会提前到循环依赖的getEarlyBeanReference这一步就会完成,singletonFactory.getObject()这个代码调用的的就是getEarlyBeanReference方法,而该方法就是返回aop代理对象

更详细的分析请参考
循环依赖

扫描二维码关注公众号,回复: 8544597 查看本文章
发布了127 篇原创文章 · 获赞 68 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/LiuRenyou/article/details/103435938
今日推荐