背景
bean的生命周期如下圖所示:
@PostConstruct注解是會(huì)被一個(gè)專門的BeanPostProcessor接口的具體實(shí)現(xiàn)類來處理的掂咒,實(shí)現(xiàn)類是:InitDestroyAnnotationBeanPostProcessor侍匙。
按照加載順序,@PostConstruct也會(huì)按照依賴順序執(zhí)行觅捆。
但是在代碼里并沒有按照期望順序執(zhí)行赦役,依賴關(guān)系如下:
@Service
@Slf4j
public class A {
@Resource
private B b;
@PostConstruct
public void init(){
log.info("A PostConstruct");
b.test();
}
}
@Service
@Slf4j
public class B {
@Resource
private C c;
@PostConstruct
public void init(){
log.info("B PostConstruct");
}
public void test(){
log.info("B Test");
}
}
@Service
public class C {
@Resource
private A a;
}
A對(duì)象里依賴了B對(duì)象,并且A的@PostConstruct方法依賴了B的@PostConstruct生成的數(shù)據(jù)栅炒,但是A的@PostConstruct掂摔,導(dǎo)致拿到的數(shù)據(jù)為空
問題分析
經(jīng)過debug,發(fā)現(xiàn)是由于循環(huán)依賴導(dǎo)致职辅,B先加載并且提前暴露棒呛,導(dǎo)致A執(zhí)行@PostConstruct時(shí)B還沒有初始化完成
為解決循環(huán)依賴,spring采用三級(jí)緩存機(jī)制域携,將實(shí)例化成功的對(duì)象加載到三級(jí)緩存簇秒,
這三級(jí)緩存的作用分別是:
singletonFactories : 進(jìn)入實(shí)例化階段的單例對(duì)象工廠的cache (三級(jí)緩存)
earlySingletonObjects :完成實(shí)例化但是尚未初始化的,提前暴光的單例對(duì)象的Cache (二級(jí)緩存)
singletonObjects:完成初始化的單例對(duì)象的cache(一級(jí)緩存)
我們?cè)趧?chuàng)建bean的時(shí)候秀鞭,會(huì)首先從cache中獲取這個(gè)bean趋观,這個(gè)緩存就是sigletonObjects。主要的調(diào)用方法是:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
//isSingletonCurrentlyInCreation()判斷當(dāng)前單例bean是否正在創(chuàng)建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
//allowEarlyReference 是否允許從singletonFactories中通過getObject拿到對(duì)象
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//其實(shí)也就是從三級(jí)緩存移動(dòng)到了二級(jí)緩存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
從上面三級(jí)緩存的分析锋边,我們可以知道皱坛,Spring解決循環(huán)依賴的訣竅就在于singletonFactories這個(gè)三級(jí)cache。這個(gè)cache的類型是ObjectFactory豆巨,定義如下:
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
這個(gè)接口在AbstractBeanFactory里實(shí)現(xiàn)剩辟,并在核心方法doCreateBean()引用下面的方法:
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);
}
}
}
這段代碼發(fā)生在createBeanInstance之后,populateBean()之前往扔,也就是說單例對(duì)象此時(shí)已經(jīng)被創(chuàng)建出來(調(diào)用了構(gòu)造器)贩猎。這個(gè)對(duì)象已經(jīng)被生產(chǎn)出來了,此時(shí)將這個(gè)對(duì)象提前曝光出來
所以在發(fā)生循環(huán)依賴時(shí)萍膛,B還未初始化吭服,所以@PostConstruct方法還未執(zhí)行
解決方案
解決循環(huán)依賴
將邏輯從@PostConstruct里抽出來