Spring生命周期和循环依赖问题

本文详细解释了Spring框架中如何处理循环依赖问题,介绍了三级缓存机制,并通过具体步骤展示了对象A与B之间的循环依赖是如何被解决的。

EverBody,直蹦主题,了解过Spring生命周期吗?

 大致流程(粗略的概括理解,当然详细的还需要更加深入的读源码):

IOC思想在图中有所展示,什么是IOC

控制反转,大家都能答出来,什么是控制反转呢?

例如,你现在30好几了,还没对象,怎么办呢,诶这个时候,有个人说有个XX婚介所,你可以在里面去找对象,里面有很多对象,这里的婚介所相当于IOC容器,然后容器里的对象,又不是平白无故出来的,是你说需要对象,并且有可能你需要漂亮的,好,那么你可以通过XML或者注解的方式,也就是图中的XmlBeanDefinitionReader读取你的需求提交的BeanDefinition定义信息中,好接下来是不是需要示例话对象了,正常思想是不是new或者反射等实例化对象,这个时候我们不需要new,我们直接交给BeanFactory工厂,交给它来通过反射找到构造器来创建你需要的对象,光创建好还不行呀,因为你的需求里,说了要年轻,貌美的,这是什么,这是属性,接下来需要填充属性了,BeanPostProcessor.before(前置增强)是什么呢,是你如果对生成的对象还不满意,你还可以进行扩展,同理BeanPostProcessor.after(后置增强)也是此意,这里用到的是AOP思想,最后,都做好后初始化生成一个完整对象。这是我最简单粗暴的理解方式。

说一说,spring是如何解决循环依赖问题的?

 我们都知道,在spring中属性的赋值是通过自动注入完成的,那么在自动注入的过程中它又是如何解决循环依赖的呢?

首先我们要明白什么是循环依赖。(三级缓存解决的是构造器的循环依赖,不是setter循环依赖)

就是假如对象A里面有一个属性是对象B,而对象B里有一个属性是对象A,这会造成什么呢?

陷入一个死循环,一直相互依赖,就会报错。这时候spring就想到了,它是怎么解决的呢?

上源码:


	// 一级缓存,存放的是已经实例化,并且初始化后的单例对象(也叫单例池)
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
	
	
	// 三级缓存,存放的是 ObjectFactory,通过 ObjectFactory 的 getObject()可以拿到已经实例化,但是并未初始化的对象
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);


	// 二级缓存,存放的是已经实例化,但是并未初始化的对象
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
	

spring 源码中解决循环依赖的核心类是:DefaultSingletonBeanRegistry ,核心的代码如下:

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 对象
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						// 通过调用 ObjectFactory 的 getObject() 获取(并不完整的)对象
						singletonObject = singletonFactory.getObject();
						// 把获取到的对象保存的二级缓存中
						this.earlySingletonObjects.put(beanName, singletonObject);
						// 从三级缓存中移除对象
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

接下来,我们再回到,对象A和对象B的问题。

通过上面源码,我们来解析当对象A在实例化时,容器通过构造器,将对象A保存到三级缓存也就是singletonFactories中,好接下来,依赖注入,好这时候发现对象B也需要实例化,此时A还只是通过构造器刚保存到singletonFactories(第三级缓存)中,我们接下来去实例化对象B,而再准备给B对象注入属性的时候发现对象A需要实例化,这时候重点来了,它是去获取缓存中的对象A,然后对象B实例化,然后B对象的在二级缓存和三级缓存中删除,再回到对象A中,B对象实例化初始化之后,A对象也初始化成功,同样A对象再三级缓存和二级缓存中删除,这样循环依赖问题就基本上解决了,下面用步骤让大家看一下。

步骤    操作    三层列表中的内容
1    开始初始化对象A    
singletonFactories:

earlySingletonObjects:

singletonObjects:

2    调用A的构造,把A放入singletonFactories    
singletonFactories:A

earlySingletonObjects:

singletonObjects:

3    开始注入A的依赖,发现A依赖对象B    
singletonFactories:A

earlySingletonObjects:

singletonObjects:

4    开始初始化对象B    
singletonFactories:A,B

earlySingletonObjects:

singletonObjects:

5    调用B的构造,把B放入singletonFactories    
singletonFactories:A,B

earlySingletonObjects:

singletonObjects:

6    开始注入B的依赖,发现B依赖对象A    
singletonFactories:A,B

earlySingletonObjects:

singletonObjects:

7    
开始初始化对象A,发现A在singletonFactories里有,则直接获取A,

把A放入earlySingletonObjects,把A从singletonFactories删除

singletonFactories:B

earlySingletonObjects:A

singletonObjects:

8    对象B的依赖注入完成    
singletonFactories:B

earlySingletonObjects:A

singletonObjects:

9    
对象B创建完成,把B放入singletonObjects,

把B从earlySingletonObjects和singletonFactories中删除

singletonFactories:

earlySingletonObjects:A

singletonObjects:B

10    对象B注入给A,继续注入A的其他依赖,直到A注入完成    
singletonFactories:

earlySingletonObjects:A

singletonObjects:B

11    
对象A创建完成,把A放入singletonObjects,

把A从earlySingletonObjects和singletonFactories中删除

singletonFactories:

earlySingletonObjects: 

singletonObjects:A,B

12    循环依赖处理结束,A和B都初始化和注入完成    
singletonFactories:

earlySingletonObjects:

singletonObjects:A,B
 

水平能力有限,如有不对,请大家指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值