Spring循环依赖流程分析

问题

我们都知道在spring中,如果两个bean,相互依赖,那么就会出现循环依赖问题,如果spring对这种问题不进行处理的话,那么就会导致创建bean 失败,所以这就是传说中的三级缓存解决循环依赖的问题。

问题一:相互依赖

Spring循环依赖流程分析_第1张图片

 从上面的流程图中我们就遇到了循环依赖的问题,也就是在创建BService 的时候,依赖了AService,难道我们再次触发创建AService的流程吗,答案是肯定不行,为了解决这个问题,我们就需要知道哪些bean是正在创建中。

Spring循环依赖流程分析_第2张图片

        在上面流程中,如果我们增加一个集合,用来存放正在创建的bean,同时用一个map来存放,实例化得到的普通对象,理论上这样我们就可以打破中循环依赖,因为我们在创建BService的时候,可以从map中获得Aservice的对象,并且进行赋值,然后完成创建Bean的生命周期。

 问题二:代理对象

        上面的解决方案在没有AOP的情况下是没有问题的,但是如果我们在初始化后需要AOP,也就说我们AService,在初始化后需要AOP,这个时候我们都知道会产生一个AService的代理对象,并且最终放在单例池中,但是如果按照上面的解决方案,我们赋值给BService的属性是个普通对象,这肯定是不可以的,所以上面的解决方案需要改进。

这里最大的问题就是,我们怎么知道到底是需要赋值普通对象还是代理对象呢?所以在spring 的源码中引入了一个第三级缓存singletonFactories。这个map中的value存放的是一个Lamda表达式,也就是一个段代码逻辑,这个逻辑就是用来判断是否需要AOP的。

首先,singletonFactories中存的是某个beanName对应的ObjectFactory,在bean的生命周期中,生成完原始对象之后,就会构造一个ObjectFactory存入singletonFactories中。这个ObjectFactory是一个函数式接口,所以支持Lambda表达式:() -> getEarlyBeanReference(beanName, mbd, bean)

上面的Lambda表达式就是一个ObjectFactory,执行该Lambda表达式就会去执行getEarlyBeanReference方法,而该方法如下:

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
	Object exposedObject = bean;
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
				SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
				exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
			}
		}
	}
	return exposedObject;
}

该方法会去执行SmartInstantiationAwareBeanPostProcessor中的getEarlyBeanReference方法,而这个接口下的实现类中只有两个类实现了这个方法,一个是AbstractAutoProxyCreator,一个是InstantiationAwareBeanPostProcessorAdapter,它的实现如下:

// InstantiationAwareBeanPostProcessorAdapter
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
	return bean;
}
// AbstractAutoProxyCreator
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
	Object cacheKey = getCacheKey(bean.getClass(), beanName);
	this.earlyProxyReferences.put(cacheKey, bean);
	return wrapIfNecessary(bean, beanName, cacheKey);
}

在整个Spring中,默认就只有AbstractAutoProxyCreator真正意义上实现了getEarlyBeanReference方法,而该类就是用来进行AOP的。上文提到的AnnotationAwareAspectJAutoProxyCreator的父类就是AbstractAutoProxyCreator。

那么getEarlyBeanReference方法到底在干什么? 首先得到一个cachekey,cachekey就是beanName。 然后把beanName和bean(这是原始对象)存入earlyProxyReferences中 调用wrapIfNecessary进行AOP,得到一个代理对象。

Spring循环依赖流程分析_第3张图片

 这样我们就很好解决了普通对象还是代理对象的问题了,但是这里仍然存在一个问题,大家思考一下,如果我们此时还有一个CService也依赖了AService。

问题三:多次生成代理对象

        为了解决上面抛出来的问题,在spring中引入了二级缓存earlySingletonObjects,也就是把我们生成的无论是代理对象还是普通对象,都缓存起来,这样其他的bean出现依赖的情况,可以直接从这个缓存中获得,不用重新生成一个代理对象,这样就保证了我们AService的唯一性。

Spring循环依赖流程分析_第4张图片

至此,通过引入三级缓存解决了,循环依赖的问题:

总结

三级缓存是通用的叫法。 一级缓存为:singletonObjects 二级缓存为:earlySingletonObjects 三级缓存为**:singletonFactories** ​

先稍微解释一下这三个缓存的作用,后面详细分析:

  • singletonObjects中缓存的是已经经历了完整生命周期的bean对象。
  • earlySingletonObjects比singletonObjects多了一个early,表示缓存的是早期的bean对象。早期是什么意思?表示Bean的生命周期还没走完就把这个Bean放入了earlySingletonObjects。
  • singletonFactories中缓存的是ObjectFactory,表示对象工厂,表示用来创建早期bean对象的工厂。

你可能感兴趣的:(@JAVA学习,spring,缓存,spring,boot)