天天看點

了解spring中循環依賴流程,絕殺面試官!

作者:言沫東

請闡述下你對spring循環依賴的了解?真的是......秃頭是有原因的......

了解spring中循環依賴流程,絕殺面試官!

下面逐層深入了解,揭開它的神秘面紗!

一、什麼是循環依賴

了解spring中循環依賴流程,絕殺面試官!

二、相關概念說明

  • spring中的一、二、三級緩存
#一級緩存:存儲所有建立完整的bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

#二級緩存:存儲完成執行個體化後的bean(createBeanInstance方法執行結束,但還未執行populateBean-屬性注入等方法)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

#三級緩存:對象工廠,通過ObjectFactory.getObject()方法,擷取到類似于二級緩存中存儲的對象
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);           
  • spring bean初始化關鍵流程說明
  1. createBeanInstance:推斷構造方法,通過反射,執行個體化一個對象;執行完該方法,會調用addSingletonFactory方法,将之放入三級緩存中
// 三級緩存中存儲的是對象工廠,擷取對象時,需調用ObjectFactory.getObject(方法)
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}           

getEarlyBeanReference方法:

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
				exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
			}
		}
		return exposedObject;
	}           
  1. populateBean:為上述建立的對象填充屬性資訊
  2. initializeBean:執行aware接口、初始化方法、AOP代理【如有需要】

三、都說spirng已經解決了循環依賴,那spring可以解決什麼情況下的循環依賴?

A、B互相依賴場景 是否支援
均采用setter方法/屬性注入 支援
均采用構造器注入 不支援
A中注入B為setter方法,B中注入A為構造器 支援
A中注入B為構造器方法,B中注入A為setter方法 不支援

四、為什麼說spring隻解決了部分情況的循環依賴?

了解spring中循環依賴流程,絕殺面試官!

在調用createBeanInstance,通過反射執行個體化對象後,會調用addSingletonFactory方法,将建立的早期對象存放到三級緩存中。是以關鍵在于三級緩存中是否存在早期對象;比如:上述場景二:均采用構造器注入,為什麼不支援該場景呢?

建立beanA時,在執行createBeanInstance(beanA)方法時,此時發現beanA依賴beanB,
則會去執行建立beanB流程,但是此時addSingletonFactory方法并沒有執行,
則三級緩存中不存在早期對象beanA,是以spring不支援“均采用構造器注入”的場景。           

上述其他場景不再一一闡述

五、隻使用二級緩存可以解決循環依賴嗎?

AOP代理本質是反射,反射出來的對象每次都是不同的,如果多個對象和beanA出現循環依賴,那麼隻有二級緩存的話就會反射出不同的對象了。