Spring三級(jí)緩存解決循環(huán)依賴
我們都知道Spring中的BeanFactory是一個(gè)IOC容器,負(fù)責(zé)創(chuàng)建Bean和緩存一些單例的Bean對(duì)象,以供項(xiàng)目運(yùn)行過(guò)程中使用。
創(chuàng)建Bean的大概的過(guò)程:
- 實(shí)例化Bean對(duì)象,為Bean對(duì)象在內(nèi)存中分配空間,各屬性賦值為默認(rèn)值
- 初始化Bean對(duì)象,為Bean對(duì)象填充屬性
- 將Bean放入緩存
首先,容器為了緩存這些單例的Bean需要一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ),比如Map {k:name; v:bean}。
而我們創(chuàng)建一個(gè)Bean就可以往Map中存入一個(gè)Bean。這時(shí)候我們僅需要一個(gè)Map就可以滿足創(chuàng)建+緩存的需求。
但是創(chuàng)建Bean過(guò)程中可能會(huì)遇到循環(huán)依賴問(wèn)題,比如A對(duì)象依賴了一個(gè)B對(duì)象,而B(niǎo)對(duì)象內(nèi)部又依賴了一個(gè)A,如下:
public class A {
B b;
}
public class B {
A a;
}
假設(shè)A和B我都定義為單例的對(duì)象,并且需要在項(xiàng)目啟動(dòng)過(guò)程中自動(dòng)注入,如下:
@Component
public class A {
@Autowired
B b;
}
@Component
public class B {
@Autowired
A a;
}
一級(jí)緩存
- 實(shí)例化A對(duì)象。
- 填充A的屬性階段時(shí)需要去填充B對(duì)象,而此時(shí)B對(duì)象還沒(méi)有創(chuàng)建,所以這里為了完成A的填充就必須要先去創(chuàng)建B對(duì)象;
- 實(shí)例化B對(duì)象。
- 執(zhí)行到B對(duì)象的填充屬性階段,又會(huì)需要去獲取A對(duì)象,而此時(shí)Map中沒(méi)有A,因?yàn)锳還沒(méi)有創(chuàng)建完成,導(dǎo)致又需要去創(chuàng)建A對(duì)象。
- 這樣,就會(huì)循環(huán)往復(fù),一直創(chuàng)建下去,只到堆棧溢出。
為什么不能在實(shí)例化A之后就放入Map?
因?yàn)榇藭r(shí)A尚未創(chuàng)建完整,所有屬性都是默認(rèn)值,并不是一個(gè)完整的對(duì)象,在執(zhí)行業(yè)務(wù)時(shí)可能會(huì)拋出未知的異常。所以必須要在A創(chuàng)建完成之后才能放入Map。
二級(jí)緩存
此時(shí)我們引入二級(jí)緩存用另外一個(gè)Map2 {k:name; v:earlybean} 來(lái)存儲(chǔ)尚未已經(jīng)開(kāi)始創(chuàng)建但是尚未完整創(chuàng)建的對(duì)象。
- 實(shí)例化A對(duì)象之后,將A對(duì)象放入Map2中。
- 在填充A的屬性階段需要去填充B對(duì)象,而此時(shí)B對(duì)象還沒(méi)有創(chuàng)建,所以這里為了完成A的填充就必須要先去創(chuàng)建B對(duì)象。
- 創(chuàng)建B對(duì)象的過(guò)程中,實(shí)例化B對(duì)象之后,將B對(duì)象放入Map2中。
- 執(zhí)行到B對(duì)象填充屬性階段,又會(huì)需要去獲取A對(duì)象,而此時(shí)Map中沒(méi)有A,因?yàn)锳還沒(méi)有創(chuàng)建完成,但是我們繼續(xù)從Map2中拿到尚未創(chuàng)建完畢的A的引用賦值給a字段。這樣B對(duì)象其實(shí)就已經(jīng)創(chuàng)建完整了,盡管B.a對(duì)象是一個(gè)還未創(chuàng)建完成的對(duì)象。
- 此時(shí)將B放入Map并且從Map2中刪除。
- 這時(shí)候B創(chuàng)建完成,A繼續(xù)執(zhí)行b的屬性填充可以拿到B對(duì)象,這樣A也完成了創(chuàng)建。
- 此時(shí)將A對(duì)象放入Map并從Map2中刪除。
二級(jí)緩存已然解決了循環(huán)依賴問(wèn)題,為什么還需要三級(jí)緩存?
從上面的流程中我們可以看到使用兩級(jí)緩存可以完美解決循環(huán)依賴的問(wèn)題,但是Spring中還有另外一個(gè)問(wèn)題需要解決,這就是初始化過(guò)程中的AOP實(shí)現(xiàn)。
AOP是Spring的重要功能,實(shí)現(xiàn)方式就是使用代理模式動(dòng)態(tài)增強(qiáng)類(lèi)的功能。
動(dòng)態(tài)單例目前有兩種技術(shù)可以實(shí)現(xiàn),一種是JDK自帶的基于接口的動(dòng)態(tài)Proxy技術(shù),一種是CGlib基于字節(jié)碼動(dòng)態(tài)生成的Proxy技術(shù),這兩種技術(shù)都是需要原始對(duì)象創(chuàng)建完畢,之后基于原始對(duì)象生成代理對(duì)象的。
那么我們發(fā)現(xiàn),在二級(jí)緩存的設(shè)計(jì)下,我們需要在放入緩存Map之前將代理對(duì)象生成好。
將流程改為:
- 實(shí)例化Bean對(duì)象,為Bean對(duì)象在內(nèi)存中分配空間,各屬性賦值為默認(rèn)值
- 如果有動(dòng)態(tài)單例,生成Bean對(duì)象的代理Proxy對(duì)象
- 初始化Proxy對(duì)象,為Bean對(duì)象填充屬性
- 將Proxy放入緩存
這樣雖然也可以解決,AOP的問(wèn)題,但是我們知道Spring中AOP的實(shí)現(xiàn)是通過(guò)后置處理器BeanPostProcessor機(jī)制來(lái)實(shí)現(xiàn)的,而后置處理器是在填充屬性結(jié)束后才執(zhí)行的。流程如下:
- 實(shí)例化對(duì)象
- 對(duì)象填充屬性
- BeanPostProcessor doBefore
- init-method
- BeanPostProcessor doAfter -- AOP是在這個(gè)階段實(shí)現(xiàn)的
所以要實(shí)現(xiàn)上面的方案,勢(shì)必需要將BeanPostProcessor階段提前或者侵入到填充屬性的流程中,那么從程序設(shè)計(jì)上來(lái)說(shuō),這樣做肯定是不美的。
三級(jí)緩存
Spring引入了第三級(jí)緩存來(lái)解決這個(gè)問(wèn)題, Map3 {k:name v:ObjectFactory} ,這個(gè)緩存的value就不是Bean對(duì)象了,而是一個(gè)接口對(duì)象由一段lamda表達(dá)式實(shí)現(xiàn)。在這段lamda表達(dá)式中去完成一些BeanPostProcessor的執(zhí)行。
- 實(shí)例化A對(duì)象之后,將A的ObjectFactory對(duì)象放入Map3中。
- 在填充A的屬性階段需要去填充B對(duì)象,而此時(shí)B對(duì)象還沒(méi)有創(chuàng)建,所以這里為了完成A的填充就必須要先去創(chuàng)建B對(duì)象。
- 創(chuàng)建B對(duì)象的過(guò)程中,實(shí)例化B的ObjectFactory對(duì)象之后,將B對(duì)象放入Map2中。
- 執(zhí)行到B對(duì)象填充屬性階段,又會(huì)需要去獲取A對(duì)象,而此時(shí)Map1中沒(méi)有A,因?yàn)锳還沒(méi)有創(chuàng)建完成,但是我們繼續(xù)從Map2中也拿不到,到Map3中獲取了A的ObjectFactory對(duì)象,通過(guò)ObjectFactory對(duì)象獲取A的早期對(duì)象,并將這個(gè)早期對(duì)象放入Map2中,同時(shí)刪除Map3中的A,將尚未創(chuàng)建完畢的A的引用賦值給a字段。這樣B對(duì)象其實(shí)就已經(jīng)創(chuàng)建完整了,盡管B.a對(duì)象是一個(gè)還未創(chuàng)建完成的對(duì)象。
- 此時(shí)將B放入Map并且從Map3中刪除。
- 這時(shí)候B創(chuàng)建完成,A繼續(xù)執(zhí)行b的屬性填充可以拿到B對(duì)象,這樣A也完成了創(chuàng)建。
- 此時(shí)將A對(duì)象放入Map并從Map2中刪除。

源碼步驟解析
- SpringBoot項(xiàng)目啟動(dòng)執(zhí)行到SpringApplication#run 中的refreshContext(context);,最終調(diào)用Spring容器的AbstractApplicationContext#refresh方法,開(kāi)始初始化BeanFactory。
- 在AbstractApplicationContext#refresh步驟中,執(zhí)行到AbstractApplicationContext#finishBeanFactoryInitialization方法,開(kāi)始完成 Bean 工廠初始化。
- 執(zhí)行到AbstracBeanFactory.preInstantiateSingletons(),開(kāi)始根據(jù)BeanFactory中的BeanDefinition信息初始化Bean對(duì)象。
- 在AbstracBeanFactory.preInstantiateSingletons()方法中,發(fā)現(xiàn)A對(duì)象的BeanDefinition,執(zhí)行AbstracBeanFactory.getBean方法,獲取A對(duì)象。
- 在AbstracBeanFactory.getBean方法中,執(zhí)行AbstracBeanFactory.doGetBean方法,獲取A對(duì)象。
- 在AbstracBeanFactory.doGetBean方法中執(zhí)行DefaultSingletonBeanRegistry#getSingleton方法,嘗試從緩存中獲取A對(duì)象的單例對(duì)象緩存。
- 到一級(jí)緩存singletonObjects中找,未找到;
- 到二級(jí)緩存earlySingletonObjects中找,未找到;
- 到三級(jí)緩存singletonFactories中找,未找到;
- 再次執(zhí)行DefaultSingletonBeanRegistry#getSingleton的重載方法,傳入lamda表達(dá)式形式的ObjectFactory對(duì)象,內(nèi)部調(diào)用AbstractAutowireCapableBeanFactory#createBean方法,嘗試創(chuàng)建A對(duì)象。
- 在AbstractAutowireCapableBeanFactory#createBean方法中,調(diào)用AbstractAutowireCapableBeanFactory#doCreateBean方法,實(shí)際執(zhí)行創(chuàng)建A對(duì)象。
- 實(shí)例化A對(duì)象,給字段賦值默認(rèn)值后,調(diào)用DefaultSingletonBeanRegistry#addSingletonFactory方法,傳入A對(duì)象的lamda表達(dá)式形式的ObjectFactory對(duì)象,將ObjectFactory對(duì)象放入三級(jí)緩存singletonFactories中,并從2級(jí)緩存earlySingletonObjects中移除(雖然這里沒(méi)有),設(shè)置A對(duì)象已經(jīng)開(kāi)始注冊(cè)。
- 此處傳入的lamda表達(dá)式,內(nèi)部調(diào)用了AbstractAutowireCapableBeanFactory#getEarlyBeanReference,此方法用來(lái)執(zhí)行實(shí)現(xiàn)了SmartInstantiationAwareBeanPostProcessor的后置處理器,比如實(shí)現(xiàn)AOP的AbstractAutoProxyCreator
- 然后開(kāi)始執(zhí)行A對(duì)象的AbstractAutowireCapableBeanFactory#populateBean,進(jìn)行屬性填充。
- 在進(jìn)行屬性填充時(shí),發(fā)現(xiàn)依賴了B對(duì)象,執(zhí)行AbstracBeanFactory.getBean方法,嘗試獲取B對(duì)象。參考上面步驟4~9。
- 執(zhí)行到B對(duì)象的屬性填充時(shí),發(fā)現(xiàn)依賴了A對(duì)象,執(zhí)行AbstracBeanFactory.getBean方法,嘗試獲取A對(duì)象。
- 在AbstracBeanFactory.doGetBean方法中執(zhí)行DefaultSingletonBeanRegistry#getSingleton方法,嘗試從緩存中獲取A對(duì)象的單例對(duì)象緩存。
- 到一級(jí)緩存singletonObjects中找,未找到;
- 到二級(jí)緩存earlySingletonObjects中找,未找到;
- 到三級(jí)緩存singletonFactories中找,找到了,并調(diào)用ObjectFactory的getObject方法獲取A對(duì)象的引用,ObjectFactory內(nèi)部調(diào)用了AbstractAutowireCapableBeanFactory#getEarlyBeanReference,獲取到A的早期對(duì)象,將A的早期對(duì)象放入二級(jí)緩存earlySingletonObjects中,并將三級(jí)緩存singletonFactories中A對(duì)象移除;
- 這樣拿到A的對(duì)象之后,B的屬性填充完畢,B初始化完成,方法return到DefaultSingletonBeanRegistry#getSingleton的重載方法時(shí),調(diào)用DefaultSingletonBeanRegistry#addSingleton方法,將B對(duì)象放入一級(jí)緩存,并將B從二三級(jí)緩存中移除(雖然已經(jīng)沒(méi)有了)。
- 這樣在return回A的流程,第11步,將A依賴的B屬性填充完整,此時(shí)A也填充完畢,初始化完成,方法繼續(xù)return到A流程的DefaultSingletonBeanRegistry#getSingleton的重載方法時(shí),調(diào)用DefaultSingletonBeanRegistry#addSingleton方法,將A對(duì)象放入一級(jí)緩存,并將A從二三級(jí)緩存中移除(此時(shí)只有二級(jí)緩存中有)。
- 這樣A和B就初始化完成了。
- 如果A或者B存在AOP,需要返回代理對(duì)象,這操作是在第9步的AbstractAutowireCapableBeanFactory#getEarlyBeanReference中完成的,B嘗試獲取A的時(shí)候,觸發(fā)了這個(gè)方法,如果A需要被代理,則是在這個(gè)方法中執(zhí)行的,這個(gè)方法最終返回了一個(gè)代理對(duì)象,并將這個(gè)對(duì)象以A的名義放入了二級(jí)緩存。
- 打完收工。
源碼
AbstractApplicationContext#refresh#finishBeanFactoryInitialization 入口類(lèi)方法 刷新上下文,初始化BeanFactory,完成工廠初始化。
DefaultListableBeanFactory#preInstantiateSingletons 準(zhǔn)備實(shí)例化單例對(duì)象
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 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);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}
AbstractBeanFactory#getBean(java.lang.String) 獲取bean對(duì)象
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
AbstractBeanFactory#doGetBean 實(shí)際執(zhí)行獲取bean對(duì)象
/**
* Return an instance, which may be shared or independent, of the specified bean.
* @param name the name of the bean to retrieve
* @param requiredType the required type of the bean to retrieve
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @param typeCheckOnly whether the instance is obtained for a type check,
* not for actual use
* @return an instance of the bean
* @throws BeansException if the bean could not be created
*/
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
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;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ′" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
AbstractAutowireCapableBeanFactory.java createBean、doCreateBean、getEarlyBeanReference
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
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);
}
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 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) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
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) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
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 " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
DefaultSingletonBeanRegistry.java 三級(jí)緩存
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name to bean instance. 一級(jí)緩存 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. 三級(jí)緩存 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. 二級(jí)緩存 */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
...
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
}
到此這篇關(guān)于Spring三級(jí)緩存解決循環(huán)依賴 的文章就介紹到這了,更多相關(guān)Spring 循環(huán)依賴內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java多線程volatile內(nèi)存語(yǔ)義解析
這篇文章主要介紹了java多線程volatile內(nèi)存語(yǔ)義解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01
SpringMVC中Model與Session的區(qū)別說(shuō)明
這篇文章主要介紹了SpringMVC中Model與Session的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
一文詳解前端和后端的數(shù)據(jù)是如何連接的(基于Spring?Boot、Django或Node.js)
這篇文章主要介紹了前端和后端的數(shù)據(jù)是如何連接的相關(guān)資料,文中通過(guò)示例介紹的非常詳細(xì),舉例講解的是基于Spring?Boot、Django或Node.js,需要的朋友可以參考下2025-01-01

