spring为什么要使用三级缓存来解决循环依赖

出现循环依赖的原因

AService依赖BService

@Service("aService")
public class AService {
    @Autowired
    BService bService;
}

BService依赖AService

@Service("bService")
public class BService {
    @Autowired
    AService aService;
}

此时就出现了循环依赖

想要搞明白循环依赖,首先要先搞清楚bean的生命周期:SpringBean生命周期-CSDN博客

AService Bean的创建流程

AService创建(doCreateBean方法)的生命周期
0. creatingSet("aService") // 将aService放入 this.singletonsCurrentlyInCreation中 表示aService正在创建中


1.创建一个AService普通对象--->singletonFactories // 通过反射创建普通对象 然后将普通对象和BeanDefinition通过一个lambda放入singletonFactories三级缓存中(该lambda会去判断是否需要进行aop等代理操作,如果没有出现循环依赖就不需要执行lambda中的内容),用于在出现循环依赖的情况下便于二级缓存拿到普通对象

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");
			}
			// 循环依赖-添加到三级缓存
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}


2.填充bService属性--->去单例池中找BService对象--->创建BService的Bean对象


3. 填充其他属性


4.其他操怍 (完成属性依赖后,继续执行初始化前(被@PostConstruct注解修饰的方法)和初始化中(实现了InitializingBean接口并重写afterPropertiesSet())的相关操作)


5.初始化后(AOP)--->如何判断之前是否有过aop呢? earlyProxyReferences这个map会存储执行过aop操作的bean


5.5 在earlySingleonObjects中找到aService对象,让该对象引用完整的AService

if (earlySingletonExposure) {
            // 会从earlyProxyReferences中获取之前创建的aService对象
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
                    // 赋值
					exposedObject = earlySingletonReference;
				}


6.放入单例池

BService Bean的创建流程

1.创建一个BService普通对象


2.填充aService属性--->去单例池中找AService对象-->creatingSet-->出现了循环依赖-去二级缓存中找->earlySingletonObjects--没找着,接着去三级缓存中去找->singletonFactories--找到后调用存放的lambda表达式->lambda-在lambda中会进行判断AService对象是否使用了aop,如果使用了则会执行代理相关操作,如果没有则不执行->AService代理对象-然后将代理的对象或者实例对象放入二级缓存中,并且删除三级缓存中的该实例->earlySingletonObjects


3.填充其他属性


4.其他操作


5.初始化后


6.放入单例池

循环依赖情况下AService如何感知是否已经进行了aop代理操作

在出现了循环依赖的情况下如果aService需要进行aop操作,在bService已经对aService进行了aop操作的情况下,aService在走到初始化后的aop操作时不应该进行aop操作,那么aService是如何知道bService已经对aService进行了aop操作的呢?

// 两个方法都在AbstractAutoProxyCreator类中,比较两个方法可以

	// bService去三级缓存中调用lambda中存放的方法,在对aService执行aop相关操作之前会先把该对象存入earlyProxyReferences中
	@Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		this.earlyProxyReferences.put(cacheKey, bean);
		// wrapIfNecessary执行aop相关操作
		return wrapIfNecessary(bean, beanName, cacheKey);
	}
	
	
		// aService初始化后 ,在执行aop相关操作之前会先判断earlyProxyReferences中是否有该bean,如果有表示执行过aop,就不需要在执行了
		@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			// wrapIfNecessary执行aop相关操作
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

三级缓存总结

1.单例池 singleonObjects:

作用获取已经创建好的bean对象不需要重复生成


2.第二级缓存 earlySingleonObjects:

作用,再出现循环依赖的情况下,如果AService不仅依赖了BService还依赖了CService,而且CService也依赖了AService,

如果没有二级缓存只有三级缓存时,如果是没有aop相关操作的话就没有问题,如果aop操作的话就会出现在BService获取了AService的代理对象后,CService还要重新获取AService代理对象,就会出现B和C依赖的AService不是同一个的情况,为了保证不重复去生产bean保证单例所有需要earlySingleonObjects二级缓存


3.第三级缓存 singletonFactories:

三级缓存的作用是让spring解决循环依赖变得更见方便一点,如果没有第三级缓存,那么当出现循环依赖时,无法拿到被依赖的对象实例。
如果三级缓存不是使用lambda的形式,没有存入普通对象和BeanDefinition,只存了普通实例对象的话,如果该普通对象初始化后需要进行aop(需要aop就需要代理操作,进行代理操作就会产生代理对象,那么就会发生不是同一个对象的情况)操作的话又会出现问题,相似的如果存入的都是代理的对象不仅浪费极大的性能,而且bean对象也不都是需要进行aop操作的,又会出现不是同一个对象的情况

spring三级缓存中最终打破循环的缓存就是第三级缓存

你可能感兴趣的:(spring,缓存,java)