循環(huán)依賴就是N個類中循環(huán)嵌套引用,如果在日常開發(fā)中我們用new 對象的方式發(fā)生這種循環(huán)依賴的話程序會在運行時一直循環(huán)調(diào)用,直至內(nèi)存溢出報錯,如下圖所示:

循環(huán)依賴的情況:
- 構(gòu)造器參數(shù)依賴
- setter方式singleton單例
- setter方式prototype多例
1、構(gòu)造器參數(shù)依賴
Spring容器會將每一個正在創(chuàng)建的Bean 標(biāo)識符放在一個“當(dāng)前創(chuàng)建Bean池”中,Bean標(biāo)識符在創(chuàng)建過程中將一直保持在這個池中,因此如果在創(chuàng)建Bean過程中發(fā)現(xiàn)自己已經(jīng)在“當(dāng)前創(chuàng)建Bean池”里時將拋出
BeanCurrentlyInCreationException異常表示循環(huán)依賴;而對于創(chuàng)建完畢的Bean將從“當(dāng)前創(chuàng)建Bean池”中清除掉。
public class StudentA {
private StudentB studentB ;
public void setStudentB(StudentB studentB) {
this.studentB = studentB;
}
public StudentA() {
}
public StudentA(StudentB studentB) {
this.studentB = studentB;
}
}
public class StudentB {
private StudentC studentC ;
public void setStudentC(StudentC studentC) {
this.studentC = studentC;
}
public StudentB() {
}
public StudentB(StudentC studentC) {
this.studentC = studentC;
}
}
public class StudentC {
private StudentA studentA ;
public void setStudentA(StudentA studentA) {
this.studentA = studentA;
}
public StudentC() {
}
public StudentC(StudentA studentA) {
this.studentA = studentA;
}
}
OK,上面是很基本的3個類,,StudentA有參構(gòu)造是StudentB。StudentB的有參構(gòu)造是StudentC,StudentC的有參構(gòu)造是StudentA ,這樣就產(chǎn)生了一個循環(huán)依賴的情況,我們都把這三個Bean交給Spring管理,并用有參構(gòu)造實例化。
<bean id="a" class="com.zfx.student.StudentA">
<constructor-arg index="0" ref="b"></constructor-arg>
</bean>
<bean id="b" class="com.zfx.student.StudentB">
<constructor-arg index="0" ref="c"></constructor-arg>
</bean>
<bean id="c" class="com.zfx.student.StudentC">
<constructor-arg index="0" ref="a"></constructor-arg>
</bean>
測試類:
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");
//System.out.println(context.getBean("a", StudentA.class));
}
}
執(zhí)行結(jié)果報錯:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
報錯原因:
Spring容器先創(chuàng)建單例StudentA,StudentA依賴StudentB,然后將A放在“當(dāng)前創(chuàng)建Bean池”中,此時創(chuàng)建StudentB,StudentB依賴StudentC ,然后將B放在“當(dāng)前創(chuàng)建Bean池”中,此時創(chuàng)建StudentC,StudentC又依賴StudentA, 但是,此時Student已經(jīng)在池中,所以會報錯,,因為在池中的Bean都是未初始化完的,所以會依賴錯誤 ,(初始化完的Bean會從池中移除)
2、setter的singleton依賴
bean的生命周期如下圖:

2.1緩存的定義
先看DefaultSingletonBeanRegistry關(guān)于緩存的定義
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
/** Names of beans that are currently in creation */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));
功能介紹:
| 緩存 | 用途 |
|---|---|
| singletonObjects | 用于存放完全初始化好的 bean,從該緩存中取出的 bean 可以直接使用 |
| earlySingletonObjects | 存放原始的 bean 對象(尚未填充屬性),用于解決循環(huán)依賴 |
| singletonFactories | 存放 bean 工廠對象,用于解決循環(huán)依賴 |
可以把singletonObjects 看做一級緩存,bean創(chuàng)建時默認(rèn)會先從singletonObjects中取bean,并且在創(chuàng)建后直接將對象放入singletonObjects中緩存;earlySingletonObjects看做二級緩存,在bean創(chuàng)建時提前將ObjectFactory暴露給singletonFactories,這樣就可以在對象創(chuàng)建完成之前也可以獲得對象的引用。
2.2bean創(chuàng)建的過程
實例化流程圖如下:

從AbstarctBeanFactory的getBean開始,是個空殼方法,直接調(diào)用doGetBean(name, null, null, false),該方法的分析如下(只分析了比較重要部分的代碼,其他地方有所省略):
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 在獲取bean的時候優(yōu)先從緩存中獲取,對于新創(chuàng)建的對象,這里是無法獲得值;對于依賴的對象,可能已經(jīng)創(chuàng)建或者正在創(chuàng)建,
//直接從緩存中獲取,可以避免重復(fù)創(chuàng)建
Object sharedInstance = getSingleton(beanName);①
if (sharedInstance != null && args == null) {
//判斷你是否FactoryBean,如果是FactoryBean類型,則調(diào)用getObject方法注入的實際對象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 對于作用域為prototype的bean,每次請求都會創(chuàng)建一個實例對象,
// 如果正在創(chuàng)建或已經(jīng)創(chuàng)建,則異常,原因為:對于prototype作用域的bean,
// Spring不會進(jìn)行緩存,因此無法提前暴露一個創(chuàng)建中的bean
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
...
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 此處用于實例化bean的依賴,比如A依賴B,如果B還未實例化,則先實例化B;
// 即調(diào)用getBean對B進(jìn)行實例化
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
registerDependentBean(dep, beanName);
getBean(dep);
}
}
// socpe="singleton"的情況
if (mbd.isSingleton()) {
// 此處的關(guān)鍵在于創(chuàng)建的匿名對象ObjectFactory及getObject方法,getObject為實際創(chuàng)建bean實例的地方
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
// 創(chuàng)建bean的關(guān)鍵
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});②
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// scope="prototype"的情況
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
//創(chuàng)建prototype對象時的前置處理:用于設(shè)置ThreadLocal變量,表示bean正在創(chuàng)建
beforePrototypeCreation(beanName);
//prototype的核心依然是調(diào)用createBean
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
//創(chuàng)建prototype對象時的后置處理:移除ThreadLocal變量
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//scope作用域為其他值的情況:比如request、session及globalSession
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
//調(diào)用實際作用域處理方法,此處也設(shè)置了ObjectFactory對象及調(diào)用的createBean方法
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
return (T) bean;
}
代碼中已經(jīng)標(biāo)識比較重要的部分,現(xiàn)在對其進(jìn)行分析,其中①處:
Object sharedInstance = getSingleton(beanName),具體調(diào)用的方法為:
//用于解決單例循環(huán)依賴的問題,此處allowEarlyReference為true,即允許早期引用(可能對象剛使用構(gòu)造函數(shù)實例化,還未設(shè)置實例的屬性等,屬于未完全實例化的對象,但是持有該對象的引用,等對象完全初始化后可直接使用)
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//先從singletonObjects中獲取,新創(chuàng)建的此處為空,新建對象在此處返回null后并不會執(zhí)行
//下面的代碼,會返回,調(diào)用②出的getSingleton(beanName, ObjectFactory)方法;
//只有在存在被依賴并且該實例正在創(chuàng)建的的情況下才會繼續(xù)執(zhí)行
Object singletonObject = this.singletonObjects.get(beanName);
//如果尚未創(chuàng)建并且此對象為正在創(chuàng)建的單例
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//從earlySingletonObjects中獲取,ObjectFactory調(diào)用后會將對象放到此處緩存
singletonObject = this.earlySingletonObjects.get(beanName);
//此處允許早期引用
if (singletonObject == null && allowEarlyReference) {
//獲取ObjectFactory工廠,使用對應(yīng)的ObjectFactory創(chuàng)建bean
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//此處調(diào)用注冊的匿名ObjectFactory方法,實際調(diào)用的是getEarlyBeanReference方法(AbstractAutowireCapableBeanFactory的doCreateBean中注冊的,暴露出的實例引用)
singletonObject = singletonFactory.getObject();
//創(chuàng)建后將此單例設(shè)置到earlySingletonObjects緩存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
標(biāo)識②中的代碼,即:
getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法,此處對對bean進(jìn)行實例化操作,并將其加入到緩存,代碼如下:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
//加鎖,避免重復(fù)執(zhí)行創(chuàng)建
synchronized (this.singletonObjects) {
//雙重檢查singletonObjects緩存,避免被其他依賴的對象創(chuàng)建完成
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
...
//前置處理:設(shè)置到singletonsCurrentlyInCreation中,表示此單例正在創(chuàng)建
beforeSingletonCreation(beanName);
boolean newSingleton = false;
...
try {
//調(diào)用getObject方法,實際就是調(diào)用createBean方法
singletonObject = singletonFactory.getObject();③
newSingleton = true;
}
catch (IllegalStateException ex) {
throw ex
}
catch (BeanCreationException ex) {
throw ex;
}
finally {
//后置處理:從singletonsCurrentlyInCreation中移除,表示對象創(chuàng)建完畢
afterSingletonCreation(beanName);
}
if (newSingleton) {
//bean完成實例化將其放入singletonObjects緩存,并清除singletonFactories和earlySingletonObjects
addSingleton(beanName, singletonObject);
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
在創(chuàng)建實例后將其放入緩存中:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
下面分析上面標(biāo)識③的代碼,實際執(zhí)行的就是注冊O(shè)bjectFactory的getObject方法,即createBean方法:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
....
try {
// 此處針對存在targetClass的bean,在實例化之前執(zhí)行注冊InstantiationAwareBeanPostProcessor
//的postProcessBeforeInstantiation方法,比如執(zhí)行AbstractAutoProxyCreateor創(chuàng)建代理類,此處以后介紹
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
//創(chuàng)建bean的實例
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
最終創(chuàng)建bean實例的地方是doCreateBean,此方法比較復(fù)雜,單最關(guān)鍵的就幾處,分別為:
- [x] createBeanInstance(beanName, mbd, args)
- [ ] applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName)
- [ ] addSingletonFactory(beanName, ObjectFactory)
- [x] populateBean(beanName, mbd, instanceWrapper)
- [x] initializeBean(beanName, exposedObject, mbd)
- [ ] getSingleton(beanName, false)
- [x] registerDisposableBeanIfNecessary
其中最重要的為上面重點標(biāo)識的部分
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
...
if (instanceWrapper == null) {
//創(chuàng)建bean的實例:實際調(diào)用構(gòu)造方法進(jìn)行反射創(chuàng)建實例
instanceWrapper = createBeanInstance(beanName, mbd, args);①
}
...
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//bean合并后的處理,Autowired注解正是通過此方法實現(xiàn)諸如類型的預(yù)解析
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);②
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 判斷是否需要早期暴露:即是單例、允許循環(huán)依賴并且已經(jīng)正在創(chuàng)建中,
// 此處設(shè)置bean的ObjectFactory,用于bean的暴露,處理循環(huán)依賴的情況
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//實例化后就暴露到singletonFactories緩存中
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
//如果不存在代理,則直接返回,否則調(diào)用SmartInstantiationAwareBeanPostProcessor
//的getEarlyBeanReference方法,即做增強處理
return getEarlyBeanReference(beanName, mbd, bean);
}
});③
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//處理屬性依賴
populateBean(beanName, mbd, instanceWrapper);④
if (exposedObject != null) {
//執(zhí)行aware、BeanPostProcessor及InitializeBean、init-method處理
exposedObject = initializeBean(beanName, exposedObject, mbd);⑤
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
//調(diào)用getSingleton方法,此處最多執(zhí)行到earlySingletonObjects緩存中取對象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
//如果對bean進(jìn)行了增強處理,此處為false
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
//處理存在依賴此bean的其他bean的情況
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
//獲得依賴此bean的bean名稱
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
//如果dependentBean已經(jīng)實例化,則放入actualDependentBeans中
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
//在此bean實例化完成之前,依賴此bean的其他bean存在已經(jīng)實例化完成的情況,
//不如何先處理依賴bean,再處理被依賴bean的情況
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// 注冊DisposableBean和destory-method,用于bean銷毀時的回調(diào)處理
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
綜上所述,對于循環(huán)依賴,比如A依賴B,B依賴A,在A進(jìn)行實例化的時候,即調(diào)用getBean的時候,執(zhí)行完createBeanInstance方法,會將A的實例通過ObjectFactory注冊到singletonFactories中提前暴露,在設(shè)置A的屬性的時候,即執(zhí)行populateBean的時候,發(fā)現(xiàn)依賴的屬性B尚未實例化,則針對B調(diào)用getBean方法,再處理B的實例化時,針對依賴的A會調(diào)用getBean的getSingleton方法,進(jìn)而調(diào)用singletonFactories緩存中注冊O(shè)bjectFactory的getObject方法,即getEarlyBeanReference方法,得到A的實例引用,然后返回處理完成B的實例化,再進(jìn)行A的實例化處理,進(jìn)而處理了循環(huán)依賴的問題。
3、setter的prototype依賴
Spring無法處理prototype的循環(huán)依賴問題,因為無法對prototype作用域的對象進(jìn)行緩存,會報如下異常:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:
Spring針對循環(huán)依賴的分析暫時到這里,其中包含了部分對bean實例化過程的分析,接下來實例化bean的時候具體的處理過程,即上述標(biāo)識的三個部分,會在下一章節(jié)進(jìn)行分析。