[Spring] 三级缓存解决循环依赖详解

什么是循环依赖

注册一个bean对象的过程:
Spring扫描class得到BeanDefinition – 根据得到的BeanDefinition去生成bean – 现根据class推断构造方法 – 根据推断出来的构造方法,反射,得到一个对象 – 填充初始对象中的属性(依赖注入) – 如果原始对象种的某个方法被AOP了,那么要根据原始对象生成一个代理对象 – 把最终生成的代理对象放入单例池(singletonObjects,也叫一级缓存)中,下次getBea你就直接从单例池拿

循环依赖就是在依赖注入的时候相互注入,如

public class AService{
    
    
	@Autowired
	private BService bService;
}
public class BService{
    
    
	@Autowired
	private AService aService;
}

三级缓存过程

Spring使用了三级缓存的策略来解决循环依赖问题,过程大致如下
创建AService的bean:
AService创建
因为暂时还没有BService,所以创建个BService
BService创建
创建过程中,因为AService已经在三级缓存中出现过,所以会进行以下操作
BService中填充AService
因为BService的属性都已经赋值了,所以BService的初始化就结束了,可以直接放到一级缓存中,完整过程为:
BService实例化过程
此时BService已经实例化完成,那么AService中的依赖就可以进行注入了:
AService实例化第二部分
完整流程图如下:
三级缓存解决循环依赖的完成流程图

简单的源码解析

首先在AbstractAutowireCapabaleBeanFactory类里(我是用ctrl+shift+alt+n找到的)的doCreateBean
先创造了一个bean原始对象,此时还没有依赖注入

		BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
    
    
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
    
    
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
        
        Object bean = instanceWrapper.getWrappedInstance();

然后将lambda表达式放入三级缓存中

        if (earlySingletonExposure) {
    
    
            if (this.logger.isTraceEnabled()) {
    
    
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }
			//放入三级缓存,这个lambda表达式是为了执行aop生成代理对象用的,如果有aop操作,就会拿到代理对象出来
            this.addSingletonFactory(beanName, () -> {
    
    
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

紧接着就是A的依赖填充

	this.populateBean(beanName, mbd, instanceWrapper);

在这个里面会走到一个getSingleton方法,也就是在缓存中找BService

	//allowEarlyReference是是否允许循环依赖
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    
    
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
    
    
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
    
    
                synchronized(this.singletonObjects) {
    
    
                	//一级缓存中找
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
    
    
                    	//二级缓存中找
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
    
    
                        	//三级缓存中找
                            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
    
    	//找到了
                            	//这里相当于上面图文分析中BService在三级缓存中找到AService
                            	//直接用lambda表达式注册,然后把他移动到二级缓存中
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }

        return singletonObject;
    }

但是显然AService肯定不会找到,然后就会重新走到createBean,创建一个BService,与A一样走到上述的getSingleton,这时会在三级缓存中找到A,然后注入

填充完成之后就会把BService放到一级缓存中,移除三级缓存中的B,然后结束

	exposedObject = this.initializeBean(beanName, exposedObject, mbd);

执行完整个BService的创建,上面的A的依赖填充才会结束,然后A也执行一遍exposedObject = this.initializeBean(beanName, exposedObject, mbd);这行代码,A也结束。

结合图文演示看代码更容易理解捏

猜你喜欢

转载自blog.csdn.net/qq_67548292/article/details/131943024