引言
假如有class A;class B闪彼。其中A依賴(lài)B,B依賴(lài)A洲劣。那么在創(chuàng)建對(duì)象時(shí)就會(huì)有循環(huán)依賴(lài)的問(wèn)題备蚓,Spring是如何解決這個(gè)問(wèn)題的呢?如果這個(gè)依賴(lài)是在構(gòu)造器中囱稽,spring還可以解決循環(huán)依賴(lài)的問(wèn)題嗎郊尝?
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
一、單例field屬性的循環(huán)依賴(lài)
這一節(jié)比較長(zhǎng)战惊,但很重要流昏。?
首先,我們需要單步調(diào)試代碼吞获,幫助我們更方便的了解spring的方法調(diào)用關(guān)系况凉。這一步可參考下述代碼:
public class TestMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext aac = new AnnotationConfigApplicationContext(TestMain.class);
aac.getBean("a");
}
}
?我們通過(guò)單步調(diào)試,可以跟蹤到獲取bean的核心方法:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1 singletonObjects各拷,存儲(chǔ)成熟的完整bean對(duì)象
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 2 earlySingletonObjects 存儲(chǔ)早期對(duì)象刁绒,早期對(duì)象初始化不完全
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3 singletonFactories 存儲(chǔ)bean工廠(chǎng),解決有后置處理器的bean烤黍,找到其最終對(duì)象的factory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
? 上述代碼中有三個(gè)緩存map知市,分別存儲(chǔ)不同時(shí)期的對(duì)象傻盟。
- singletonObjects存儲(chǔ)完整的bean,bean完全創(chuàng)建完成嫂丙,將其放入singletonObjects娘赴。獲取bean也先由這里獲取。
- earlySingletonObjects存儲(chǔ)早期對(duì)象跟啤,該早期對(duì)象中存在不可用的屬性值诽表。
- singletonFactories存儲(chǔ)bean工廠(chǎng)對(duì)象,是經(jīng)過(guò)AOP增強(qiáng)的最終工廠(chǎng)對(duì)象隅肥。
? 上述代碼中竿奏,我們看到有三級(jí)緩存,這是解決循環(huán)依賴(lài)的關(guān)鍵武福。簡(jiǎn)單看下getSingleton做了以下幾件事:查詢(xún)一級(jí)緩存singletonObjects议双,然后查詢(xún)二級(jí)緩存earlySingletonObjects痘番,最后查詢(xún)?nèi)?jí)緩存singletonFactory捉片,同時(shí)將bean放到二級(jí)緩存,并由三級(jí)緩存清除汞舱。
但是這里對(duì)一個(gè)全新的bean伍纫,返回還是null,而且各級(jí)緩存中的對(duì)象是什么時(shí)候放進(jìn)去的呢昂芜?我們先來(lái)看下:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
......
Object sharedInstance = getSingleton(beanName);
......
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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);
}
......
上述分析的getSingleton是第5行莹规,這里我們先關(guān)注第9行的getSingleton方法。單例模式下泌神,通過(guò)getSingleton(為和第5行的getSingleton區(qū)分良漱,我們稱(chēng)這個(gè)為第二個(gè)getSingleton)獲取bean,實(shí)現(xiàn)如下:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
......
beforeSingletonCreation(beanName);
......
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
......
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
}
......
}
? 上面有singletonFactory.getObject()欢际,該方法的實(shí)現(xiàn)是在入?yún)⒅卸x的母市,即createBean(beanName, mbd, args)(后面詳細(xì)分析)。此外還有一個(gè)addSingleton的方法损趋,實(shí)現(xiàn)如下:
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);
}
}
? 到這里患久,我們可以看到,一個(gè)全新的對(duì)象浑槽,是通過(guò)createBean創(chuàng)建完成蒋失,然后放到singletonObjects的。
? 接下來(lái)我們分析:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
......
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
......
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
......
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
......
return exposedObject;
}
? 在創(chuàng)建bean的時(shí)候桐玻,先調(diào)用createBeanInstance生成一個(gè)BeanWrapper篙挽。他的最終調(diào)用只是newInstance了一個(gè)對(duì)象,沒(méi)有對(duì)對(duì)象進(jìn)行初始化镊靴,這就為后續(xù)的aop增強(qiáng)铣卡,以及循環(huán)對(duì)象的注入提供了條件观腊。
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
try {
ReflectionUtils.makeAccessible(ctor);
return ctor.newInstance(args);
}
......
}
? 繼續(xù)回到doCreateBean方法,如下所示:
if (earlySingletonExposure) {
......
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
? 當(dāng)bean處于創(chuàng)建中算行,并且存在循環(huán)依賴(lài)時(shí)梧油,做了addSingletonFactory操作,如下所示:
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);
}
}
}
? 這里我們可以看到州邢,singletonFactory被放到了singletonFactories儡陨,singletonFactory是new的那個(gè)ObjectFactory。這里ObjectFactory為什么要這么定義量淌,還有為什么需要使用singletonFactories骗村?二級(jí)緩存不能解決循環(huán)依賴(lài)問(wèn)題?這就需要關(guān)注getEarlyBeanReference呀枢。
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return null;
}
}
}
}
return exposedObject;
}
? getEarlyBeanReference是由三級(jí)緩存singletonFactory中獲取對(duì)象的實(shí)現(xiàn)方法胚股,它調(diào)用的是org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference方法。實(shí)現(xiàn)如下:
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
return wrapIfNecessary(bean, beanName, cacheKey);
}
繼續(xù)看下wrapIfNecessary裙秋,org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
......
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
? 上面通過(guò)createProxy方法琅拌,創(chuàng)建了帶有aop增強(qiáng)設(shè)置的方法。到此摘刑,第三級(jí)緩存singletonFactory的作用我們就清楚了进宝,主要是解決aop增強(qiáng)的實(shí)現(xiàn)。到這里我們可以得知new的ObjectFactory枷恕,最終幫助我們拿到了aop增強(qiáng)后的對(duì)象党晋。
? 接下來(lái)需要注意的方法是populateBean:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
......
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
applyPropertyValues(beanName, mbd, bw, pvs);
}
? populateBean用于填充對(duì)象的屬性。這里會(huì)填充對(duì)象依賴(lài)的其他對(duì)象信息徐块。上述代碼的postProcessPropertyValues方法未玻,最終會(huì)調(diào)用到:
org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates。
protected Map<String, Object> findAutowireCandidates(
String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
......
for (String candidateName : candidateNames) {
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
result.put(candidateName, getBean(candidateName));
}
}
......
}
? 上面的candidateName表示依賴(lài)的對(duì)象名稱(chēng)(B)胡控,這里可以看到扳剿,對(duì)于依賴(lài)的對(duì)象,又會(huì)重新調(diào)用getBean獲取bean對(duì)象铜犬。具體調(diào)用舞终,可以參考下面的調(diào)用堆棧圖:
? 我們清楚了三級(jí)緩存的作用,下面我們結(jié)合上述分析癣猾,看看三級(jí)緩存是如何解決循環(huán)依賴(lài)問(wèn)題的敛劝。
? 假設(shè)A依賴(lài)B,B依賴(lài)A纷宇。獲取A時(shí)夸盟,A和B在三級(jí)緩存都不存在,因此第一個(gè)getSingleton返回null像捶。之后會(huì)調(diào)doGetBean創(chuàng)建A上陕,創(chuàng)建A時(shí)桩砰,先調(diào)createBeanInstance得到一個(gè)newInstance的沒(méi)有實(shí)例化的對(duì)象。然后把對(duì)象A的工廠(chǎng)類(lèi)放到singletonFactories释簿,這里需要提的是亚隅,若A有做AOP增強(qiáng),那么放到singletonFactories的就是AOP增強(qiáng)后工廠(chǎng)類(lèi)庶溶。
? 接下來(lái)會(huì)在創(chuàng)建A中執(zhí)行populateBean方法煮纵,進(jìn)一步會(huì)調(diào)getBean,獲取B偏螺,這將重復(fù)上述過(guò)程行疏。
? 在獲取B時(shí),創(chuàng)建B的方法也會(huì)走到populateBean套像,這時(shí)酿联,B又會(huì)獲取A的對(duì)象。這時(shí)第二次獲取A對(duì)象的getBean方法夺巩,會(huì)在執(zhí)行第一個(gè)getSingleton時(shí)贞让,檢查到第三級(jí)緩存singletonFactories中有A的工廠(chǎng)方法,于是將對(duì)象A放到早期對(duì)象緩存earlySingletonObjects中劲够。這輪查詢(xún)震桶,有得到一個(gè)早期的對(duì)象A休傍,B將使用這個(gè)早期的對(duì)象A征绎,完成對(duì)象B的創(chuàng)建。
? B對(duì)象創(chuàng)建完成磨取,A對(duì)象還在earlySingletonObjects中人柿,在getSingleton中最后的addSingleton方法,會(huì)將對(duì)象A由二級(jí)緩存放到一級(jí)緩存singletonObjects中忙厌,這時(shí)獲取到完整的對(duì)象A凫岖。
二、構(gòu)造器中的循環(huán)依賴(lài)
? 接下來(lái)我們?cè)倏纯捶昃唬瑂pring能否處理構(gòu)造器中包含循環(huán)依賴(lài)的問(wèn)題哥放。
@Component
public class A {
private B cb;
@Autowired
A(B b){
this.cb = b;
}
}
@Component
public class B {
private A ca;
@Autowired
B(A a){
this.ca = a;
}
}
? 同樣,我們還是假設(shè)A的構(gòu)造器中依賴(lài)B爹土,B的構(gòu)造器中依賴(lài)A甥雕。我們回顧上述第二個(gè)getSingleton中的beforeSingletonCreation方法:
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
? 這里,singletonsCurrentlyInCreation保存的是當(dāng)前正在創(chuàng)建胀茵,但是還沒(méi)有創(chuàng)建完畢的類(lèi)社露,根據(jù)上述對(duì)循環(huán)依賴(lài)的分析,當(dāng)?shù)诙蝿?chuàng)建A時(shí)琼娘,singletonsCurrentlyInCreation中已經(jīng)包含A峭弟。這里附鸽,我們看下singletonsCurrentlyInCreation的定義:
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
? 這里,使用的是ConcurrentHashMap來(lái)保存瞒瘸,add方法實(shí)現(xiàn)為:
public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; }
? 也就是說(shuō)坷备,當(dāng)map中已經(jīng)包含A時(shí),ConcurrentHashMap的put方法會(huì)返回舊值(非null)情臭,這里的add方法會(huì)返回false击你。通過(guò)調(diào)試,發(fā)現(xiàn)inCreationCheckExclusions也是空谎柄,因此丁侄,這時(shí)會(huì)拋BeanCurrentlyInCreationException異常,導(dǎo)致創(chuàng)建A失敗朝巫。因此鸿摇,spring無(wú)法直接解決構(gòu)造器中包含循環(huán)依賴(lài)的對(duì)象。
? 到這里劈猿,我們會(huì)問(wèn)到拙吉,spring為什么要這么設(shè)計(jì)呢?其實(shí)原因很簡(jiǎn)單揪荣,spring的早期對(duì)象A沒(méi)有被初始化筷黔,當(dāng)newInstatnce一個(gè)對(duì)象B時(shí),會(huì)執(zhí)行B的構(gòu)造方法仗颈,如果B的構(gòu)造方法中對(duì)早期對(duì)象A進(jìn)行操作佛舱,可能會(huì)拋異常。
? 那么挨决。Spring無(wú)法解決這個(gè)問(wèn)題嗎请祖?不是的,在構(gòu)造函數(shù)的循環(huán)依賴(lài)參數(shù)前使用@Lazy注解脖祈,即可在構(gòu)造器中使用循環(huán)依賴(lài)肆捕。
@Component
public class B {
private A ca;
@Autowired
B(@Lazy A a){
this.ca = a;
}
}
三、總結(jié)
1.spring通過(guò)使用三級(jí)緩存來(lái)解決循環(huán)依賴(lài)的問(wèn)題盖高,之所以使用三級(jí)緩存而不是二級(jí)緩存慎陵,是因?yàn)檫€需要處理aop增強(qiáng)的類(lèi)。
2.spring無(wú)法直接解決構(gòu)造器循環(huán)依賴(lài)喻奥,但可以使用@Lazy注解實(shí)現(xiàn)構(gòu)造器的循環(huán)依賴(lài)