1.背景說明
● 循環(huán)依賴是什么?
有一個(gè)Bean為AService,另一個(gè)Bean為BService。
AService里面引用了屬性BService,BService里面又引用了屬性AService,這樣在加載Bean的時(shí)候,造成對(duì)彼此的循環(huán)依賴。
這樣會(huì)導(dǎo)致Bean無法加載。
● 解決循環(huán)依賴的思路
說明:這里只解決單例bean的循環(huán)依賴問題。
核心思路:只需要增加一個(gè) 緩存 來存放 原始對(duì)象 即可,Spring解決此類循環(huán)依賴主要是靠三級(jí)緩存在【屬性注入】階段產(chǎn)生作用。
具體做法:在創(chuàng)建 AService 時(shí),實(shí)例化后將 原始對(duì)象 存放到緩存中(提早暴露),然后依賴注入時(shí)發(fā)現(xiàn)需要 BService,便會(huì)去創(chuàng)建 BService,實(shí)例化后同樣將 原始對(duì)象 存放到緩存中,然后依賴注入時(shí)發(fā)現(xiàn)需要 AService 便會(huì)從緩存中取出并注入,這樣 BService 就完成了創(chuàng)建,隨后 AService 也就能完成屬性注入,最后也完成創(chuàng)建。這樣就打破了環(huán)形調(diào)用,避免循環(huán)依賴問題。
2.三級(jí)緩存
● 一級(jí)緩存:SingletonObjects,緩存的是已經(jīng)實(shí)例化、屬性注入、初始化后的bean對(duì)象。
● 二級(jí)緩存:earlySingletonObjects,緩存的是實(shí)例化后,但未屬性注入、初始化的Bean對(duì)象,用于提前暴露Bean
● 三級(jí)緩存:singletonFactories,緩存的是一個(gè)ObjectFactory,主要作用是生成原始對(duì)象進(jìn)行AOP操作后的代理對(duì)象
3.源碼分析
3.1 入口
從 AbstractApplicationContext.java的 這個(gè)方法進(jìn)去:
// 初始化 非懶加載的單例 bean
beanFactory.preInstantiateSingletons();
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
進(jìn)入到 DefaultListableBeanFactory的preInstantiateSingletons方法:
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
3.2 getBean方法
DefaultListableBeanFactory中,進(jìn)入getBean
這里獲取的是這種類型的bean:
(1)非抽象的BeanDefinition
(2)單例的BeanDefinition
(3)非懶加載的BeanDefinition
else {
getBean(beanName);
}
3.3 doGetBean方法
實(shí)際干活的是 AbstractBeanFactory中的 doGetBean
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException
如果不存在已有的單例對(duì)象,且beanDefination是單例,那么進(jìn)入 createBean方法
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);
}
3.4 createBean方法
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException
createBean方法 返回一個(gè)Object類型
核心邏輯:
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
3.5 doCreateBean方法
3.5.1 實(shí)例化對(duì)象
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException
● 首先,實(shí)例化一個(gè)對(duì)象:
instanceWrapper = createBeanInstance(beanName, mbd, args)
3.5.2 加入三級(jí)緩存
接著,把創(chuàng)建對(duì)象的lambda表達(dá)式放到三級(jí)緩存。
這里是為了避免后期的循環(huán)依賴,所以在bean初始化完成前將創(chuàng)建實(shí)例的ObjectFactory加入工廠。
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));
}
說明:
(1)getEarlyBeanReference(beanName, mbd, bean) 方法 會(huì)返回遍歷工廠內(nèi)的所有后置處理器,去處理原始的bean,并返回最終經(jīng)過層層包裝后的 代理對(duì)象
(2)這里并不會(huì)馬上執(zhí)行g(shù)etEarlyBeanReference方法,有循環(huán)依賴的時(shí)候才執(zhí)行。
3.5.3 屬性賦值
場(chǎng)景:AService 中要注入屬性BService
進(jìn)入populateBean方法
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
核心方法:
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
applyPropertyValues中的核心方法:
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
點(diǎn)進(jìn)去:
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
核心方法:resolveReference(argName, ref),點(diǎn)進(jìn)去:
else {
String resolvedName;
if (beanType != null) {
NamedBeanHolder<?> namedBean =
this.beanFactory.resolveNamedBean(beanType);
bean = namedBean.getBeanInstance();
resolvedName = namedBean.getBeanName();
} else {
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
bean = this.beanFactory.getBean(resolvedName);
}
this.beanFactory.registerDependentBean(resolvedName, this.beanName);
}
注意:這里開始無限套娃之旅,即:
(1)這里有一句:bean = this.beanFactory.getBean(resolvedName),在該場(chǎng)景下,作用是獲取屬性Bservice。
(2)然后 B在創(chuàng)建過程中,最終又會(huì)執(zhí)行這句bean = this.beanFactory.getBean(resolvedName),去獲取屬性Aservice
3.6 循環(huán)依賴的閉環(huán)
● 閉環(huán)形成的關(guān)鍵點(diǎn)
當(dāng) Aservice --> Bservice --> Aservice 這個(gè)過程,進(jìn)行到第二次 獲取 Aservice 的時(shí)候,會(huì)通過 getSingleton 方法
獲取Aservice,即:
可以看到在第三級(jí)緩存中調(diào)用了 singletonFactories.get(beanName)。
按照上文所說,會(huì)觸發(fā)執(zhí)行有 AOP 操作,返回代理對(duì)象。如果沒有AOP操作的話,返回原始對(duì)象。
此外,還會(huì)把Aservice上移到二級(jí)緩存中、并刪除三級(jí)緩存的數(shù)據(jù)。
● Bservice創(chuàng)建完成
如此一來,容器在創(chuàng)建Bservice的時(shí)候,就可以拿到 Aservice,完成BService的創(chuàng)建,并將Bservice加入一級(jí)緩存。
● Aservice創(chuàng)建完成
當(dāng)Bservice創(chuàng)建完成后,就可以在Aservice中完成屬性Bservice的注入,從而完成AService的創(chuàng)建,將Aservice加入一級(jí)緩存。
4.總結(jié)
梳理整個(gè)過程如下:
● 首先會(huì)獲取 AService 對(duì)應(yīng)的 Bean 對(duì)象。
先是調(diào)用 doGetBean() 中的第一個(gè) getSingleton(beanName) 判斷是否有該 Bean 的實(shí)例,有就直接返回了。(顯然這里沒有)
然后調(diào)用 doGetBean() 中的第二個(gè) getSingleton() 方法來執(zhí)行 doCreateBean() 方法。
先進(jìn)行實(shí)例化操作(也就是利用構(gòu)造函數(shù)實(shí)例化),此時(shí)實(shí)例化后生成的是原始對(duì)象。
將原始對(duì)象通過 lambda表達(dá)式 進(jìn)行封裝成 ObjectFactory 對(duì)象,通過 addSingletonFactory 加入三級(jí)緩存中。
然后再進(jìn)行屬性注入,此時(shí)發(fā)現(xiàn)需要注入 BService 的 Bean,會(huì)通過 doGetBean() 去獲取 BService 對(duì)應(yīng)的 Bean。
● 獲取BService 對(duì)應(yīng)的 Bean。
同樣調(diào)用 doGetBean() 中的第一個(gè) getSingleton(beanName) 判斷是否有該 Bean 的實(shí)例,顯然這里也是不會(huì)有 BService 的 Bean 的。
然后只能調(diào)用 doGetBean() 中的第二個(gè) getSingleton() 方法來執(zhí)行 doCreateBean() 方法來創(chuàng)建一個(gè) BService 的 Bean。
同樣地先進(jìn)行實(shí)例化操作,生成原始對(duì)象后封裝成 ObjectFactory 對(duì)象放入三級(jí)緩存中。
然后進(jìn)行屬性注入,此時(shí)發(fā)現(xiàn)需要注入 AService 的 Bean。
● 第二次獲取AService 對(duì)應(yīng)的 Bean
此時(shí)調(diào)用調(diào)用 doGetBean() 中的第一個(gè) getSingleton(beanName) 查找是否有 AService 的 Bean。此時(shí)會(huì)觸發(fā)三級(jí)緩存,也就是調(diào)用 singletonFactories.get(beanName)。
因?yàn)槿?jí)緩存中有 AService 的原始對(duì)象封裝的 ObjectFactory 對(duì)象,所以可以獲取到的代理對(duì)象或原始對(duì)象,并且上移到二級(jí)緩存中,提前暴露給 BService 調(diào)用。
所以 BService 可以完成屬性注入,然后進(jìn)行初始化后,將 Bean 放入一級(jí)緩存,這樣 AService 也可以完成創(chuàng)建。