循环依赖指多个对象的建立过程当中均须要注入对方对象,以下所示java
class A{ B b; public A(){ } public A(B b){ this.b = b; } public void setB(B b){ this.b = b; } }
class B{ A a; public B(){ } public B(A a){ this.a = a; } public void setA(A a){ this.a = a; } }
Spring中将对象建立分为以下两步面试
而且引入三级缓存,来提早暴露对象引用,从而解决循环依赖的问题spring
假设A和B的建立中,field均须要对方的引用,在refresh方法进行到finishBeanFactoryInitialization(beanFactory)时,会开始建立非懒加载的singleton,这里会先进入preInstantiateSingletons方法,根据beanName调用getBean方法,假设此时A先进行建立,那么会进入下面方法segmentfault
doGetBean
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean缓存
getSingleton---1ide
@Override @Nullable public Object getSingleton(String beanName) { return getSingleton(beanName, true); } @Nullable 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<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
首先调用上面方法先从singletonObjects中场是获取,发现为null,因为isSingletonCurrentlyInCreation为false(对象未在建立过程当中),所以直接返回nullpost
if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
其中执行DefaultSingletonBeanRegistry#getSingleton(beanName,ObjectFactory)方法简化版以下,传入的ObjectFactory实现类是一个lambda表达式,也即用createBean方法重写ObjectFactory#getObject方法this
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { boolean newSingleton = false; try { singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { } } catch (BeanCreationException ex) { } finally { } if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } }
这里第一行调用singletonFactory.getObject方法会触发createBean,又触发AbstractAutowireCapableBeanFactory#doCreateBean方法中主题步骤以下.net
实例化bean代理
将bean放入三级缓存singletonFactories
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)); }
其中调用addSingletonFactory方法以下,此处传入的lambda表达式给定的即为ObjectFactory对象,在执行其getObject方法时,即执行getEarlyBeanReference
方法(这里须要留意!)
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { 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); } } }
A执行populateBean,开始注入属性b,因为B的对象还未建立,getSingleton---1(b)为null,这时触发B对象建立
B进行实例化
B放入三级缓存
B执行populateBean,开始注入属性a,调用getSingleton---1方法获取a,发现一级缓存singletonObject中没有对应对象,且正在建立中,则从二级缓存earlySingletonObjects中获取,发现仍然为null且allowEarlyReference默认为true,则去三级缓存中去获取,最终从三级缓存中获取,因为放入三级缓存时,lambda表达式为() -> getEarlyBeanReference(beanName, mbd, bean),因此会调用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; }
这里在遍历后置处理器的过程当中,会调用到AbstractAutoProxyCreator的postProcessAfterInitialization方法,此方法会判断A是否被代理,若是被代理会建立代理对象并返回,以后将原有A对象从三级缓存中删除,并将A的代理对象加入到二级缓存earlySingletonObjects中,以后将A的代理对象注入给B
B执行initializeBean方法,调用后置处理器及afterProperties方法,这里提到后置处理器,一样会判断B是否被代理,若是被代理则会建立B的代理对象并返回
B建立结束以后,会回到getSingleton---2方法,调用addSingleton(beanName, singletonObject);方法,以下
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
这里会将B从三级缓存中删除,并加入到一级缓存中
将B建立好的对象注入到A中
A执行initializeBean方法,进行初始化,初始化完成
回到getSingleton--2,执行DefaultSingletonBeanRegistry#addSingleton
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
将A从二级缓存中删除,并加入到一级缓存中
从上面步骤能够看出,
三级缓存分别用于存放下面三类对象
一级缓存singletonObjects
彻底建立好的对象,若是被代理,则存放代理对象
二级缓存earlySingletonObjects
未彻底建立好的代理对象
三级缓存singletonFactories
只进行了实例化,未进行属性注入和初始化的对象
为什么上面机制生效
因为提早暴露了A对象的引用!,于是在B注入好不完整的A对象后,B觉得本身建立好了,这时会注入给A,同时A也会将此B对象看成建立好的,并注入给本身,这样A就真建立完成了,因为B保留着A的引用,这样B也就真建立完成了
如上在有循环依赖的状况下,假设A被代理,那么须要将A的代理对象注入给B,这时经过getSingleton方法从三级缓存获取对象的过程当中,因为ObjectFactory的getObject方法被重写为AbstractAutowireCapableBeanFactory#getEarlyBeanReference方法,这时会触发后置处理器的执行,会调用AbstractAutoProxyCreator的postProcessAfterInitialization方法,并返回代理对象,以后将代理对象返回用于注入,并放入二级缓存,若是A和除了B的其余对象也构成循环依赖,以后直接从二级缓存中获取A的代理对象便可
在没有循环依赖的状况下,不会使用到二级缓存,若是A被代理,那么A会在彻底建立后,在调用后置处理器序列时,会调用AbstractAutoProxyCreator的postProcessAfterInitialization方法,并返回代理对象
从上能够看出,
Spring循环依赖三级缓存是否能够减小为二级缓存? - SegmentFault 思否