栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring源码解析:三级缓存与循环依赖

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring源码解析:三级缓存与循环依赖

循环依赖

Spring的循环依赖指的是两个或以上的bean对象互相作为对方的属性,例如A类中存在属性B,B类中存在属性A。Spring在创建实例化A时发现需要注入B类,就先去创建B类,在创建B类时发现需要注入A类,这时候又去寻找A类。这就是循环依赖,如下图:

如果按照Spring普通的方式去进行实例化,是不可避免循环依赖的。我们从源码开始,一步一步分析Spring是如何解决循环依赖的。首先是从获取bean开始。我们从doGetBean方法开始进入,注意这个getSingleton(beanName),顾名思义就是根据beanName获取一个单例对象。假如我现在是在获取A类的Bean,那么这里就是通过A的beanName获取bean A。点击进入方法。

这里包括源码的注释和翻译我一起贴出来

	
	 
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 从单例缓存中获取单例对象
		Object singletonObject = this.singletonObjects.get(beanName);
		// 如果singletonObject为空,并且对象正在创建中,就进行下一步
		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) {
						// 调用getObject()方法创建一个单例对象
						singletonObject = singletonFactory.getObject();
						// 放入二级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
						// 从单例工厂中移除
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

首先是从一级singletonObjects中获取bean,这个singletonObjects是一个存放创建完毕的Bean的Map。很明显A正在创建中,肯定获取不到。返回上一步,如果是正在创建的bean的作用域是原型模式,那么就直接抛异常

但是在实例化之前,Spring会将A类标记为正在创建中的bean,存入一个集合singletonsCurrentlyInCreation中,方便后面处理循环依赖的bean。在DefaultSingletonBeanRegistry类中有一个方法,顾名思义就是在单例创建之前执行的方法。

	
	// 单例创建之前的回调。 

默认实现将单例注册为当前正在创建。 protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }

接下来就是去创建bean A。Spring中一般做事的都是do开头的,所以直接去寻找doCreateBean去实例化A。具体的实例化过程我就不写了,关键在doCreateBean方法中这段代码,如果A类是单例、允许循环依赖、并且是正在创建中的单例。就将bean 存入缓存中,

这个addSingletonFactory函数式接口的作用就是将bean存入三级缓存。方便其他bean需要注入该bean的时候可以直接获取

到这里A类就实例化完毕,在为A注入属性的时候九华发现B类需要注入,Spring就会去创建B类的Bean。再次进入我们第一次贴的getSingleton(beanName)方法时,就可以获取到A的bean了。通过我们存入三级缓存的对象工厂直接拿到对象A。B创建完毕后A也能注入了。大致的流程如下图:

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/768771.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号