欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring三級緩存解決循環(huán)依賴

 更新時間:2021年12月24日 09:19:16   作者:小丸子的呆地  
本文主要介紹了Spring三級緩存解決循環(huán)依賴,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

我們都知道Spring中的BeanFactory是一個IOC容器,負責創(chuàng)建Bean和緩存一些單例的Bean對象,以供項目運行過程中使用。

創(chuàng)建Bean的大概的過程:

  • 實例化Bean對象,為Bean對象在內存中分配空間,各屬性賦值為默認值
  • 初始化Bean對象,為Bean對象填充屬性
  • 將Bean放入緩存

首先,容器為了緩存這些單例的Bean需要一個數(shù)據(jù)結構來存儲,比如Map {k:name; v:bean}。

而我們創(chuàng)建一個Bean就可以往Map中存入一個Bean。這時候我們僅需要一個Map就可以滿足創(chuàng)建+緩存的需求。
但是創(chuàng)建Bean過程中可能會遇到循環(huán)依賴問題,比如A對象依賴了一個B對象,而B對象內部又依賴了一個A,如下:

public class A {
    B b;
}
public class B {
    A a;
}

假設A和B我都定義為單例的對象,并且需要在項目啟動過程中自動注入,如下:

@Component
public class A {
    @Autowired
    B b;
}

@Component
public class B {
    @Autowired
    A a;
}

一級緩存

  • 實例化A對象。
  • 填充A的屬性階段時需要去填充B對象,而此時B對象還沒有創(chuàng)建,所以這里為了完成A的填充就必須要先去創(chuàng)建B對象;
  • 實例化B對象。
  • 執(zhí)行到B對象的填充屬性階段,又會需要去獲取A對象,而此時Map中沒有A,因為A還沒有創(chuàng)建完成,導致又需要去創(chuàng)建A對象。
  • 這樣,就會循環(huán)往復,一直創(chuàng)建下去,只到堆棧溢出。

為什么不能在實例化A之后就放入Map?

因為此時A尚未創(chuàng)建完整,所有屬性都是默認值,并不是一個完整的對象,在執(zhí)行業(yè)務時可能會拋出未知的異常。所以必須要在A創(chuàng)建完成之后才能放入Map。

二級緩存

此時我們引入二級緩存用另外一個Map2 {k:name; v:earlybean} 來存儲尚未已經(jīng)開始創(chuàng)建但是尚未完整創(chuàng)建的對象。

  • 實例化A對象之后,將A對象放入Map2中。
  • 在填充A的屬性階段需要去填充B對象,而此時B對象還沒有創(chuàng)建,所以這里為了完成A的填充就必須要先去創(chuàng)建B對象。
  • 創(chuàng)建B對象的過程中,實例化B對象之后,將B對象放入Map2中。
  • 執(zhí)行到B對象填充屬性階段,又會需要去獲取A對象,而此時Map中沒有A,因為A還沒有創(chuàng)建完成,但是我們繼續(xù)從Map2中拿到尚未創(chuàng)建完畢的A的引用賦值給a字段。這樣B對象其實就已經(jīng)創(chuàng)建完整了,盡管B.a對象是一個還未創(chuàng)建完成的對象。
  • 此時將B放入Map并且從Map2中刪除。
  • 這時候B創(chuàng)建完成,A繼續(xù)執(zhí)行b的屬性填充可以拿到B對象,這樣A也完成了創(chuàng)建。
  • 此時將A對象放入Map并從Map2中刪除。

二級緩存已然解決了循環(huán)依賴問題,為什么還需要三級緩存?

從上面的流程中我們可以看到使用兩級緩存可以完美解決循環(huán)依賴的問題,但是Spring中還有另外一個問題需要解決,這就是初始化過程中的AOP實現(xiàn)。

AOP是Spring的重要功能,實現(xiàn)方式就是使用代理模式動態(tài)增強類的功能。

動態(tài)單例目前有兩種技術可以實現(xiàn),一種是JDK自帶的基于接口的動態(tài)Proxy技術,一種是CGlib基于字節(jié)碼動態(tài)生成的Proxy技術,這兩種技術都是需要原始對象創(chuàng)建完畢,之后基于原始對象生成代理對象的。

那么我們發(fā)現(xiàn),在二級緩存的設計下,我們需要在放入緩存Map之前將代理對象生成好。
將流程改為:

  • 實例化Bean對象,為Bean對象在內存中分配空間,各屬性賦值為默認值
  • 如果有動態(tài)單例,生成Bean對象的代理Proxy對象
  • 初始化Proxy對象,為Bean對象填充屬性
  • 將Proxy放入緩存

這樣雖然也可以解決,AOP的問題,但是我們知道Spring中AOP的實現(xiàn)是通過后置處理器BeanPostProcessor機制來實現(xiàn)的,而后置處理器是在填充屬性結束后才執(zhí)行的。流程如下:

  • 實例化對象
  • 對象填充屬性
  • BeanPostProcessor doBefore
  • init-method
  • BeanPostProcessor doAfter -- AOP是在這個階段實現(xiàn)的

所以要實現(xiàn)上面的方案,勢必需要將BeanPostProcessor階段提前或者侵入到填充屬性的流程中,那么從程序設計上來說,這樣做肯定是不美的。

三級緩存

Spring引入了第三級緩存來解決這個問題, Map3 {k:name v:ObjectFactory} ,這個緩存的value就不是Bean對象了,而是一個接口對象由一段lamda表達式實現(xiàn)。在這段lamda表達式中去完成一些BeanPostProcessor的執(zhí)行。

  • 實例化A對象之后,將A的ObjectFactory對象放入Map3中。
  • 在填充A的屬性階段需要去填充B對象,而此時B對象還沒有創(chuàng)建,所以這里為了完成A的填充就必須要先去創(chuàng)建B對象。
  • 創(chuàng)建B對象的過程中,實例化B的ObjectFactory對象之后,將B對象放入Map2中。
  • 執(zhí)行到B對象填充屬性階段,又會需要去獲取A對象,而此時Map1中沒有A,因為A還沒有創(chuàng)建完成,但是我們繼續(xù)從Map2中也拿不到,到Map3中獲取了A的ObjectFactory對象,通過ObjectFactory對象獲取A的早期對象,并將這個早期對象放入Map2中,同時刪除Map3中的A,將尚未創(chuàng)建完畢的A的引用賦值給a字段。這樣B對象其實就已經(jīng)創(chuàng)建完整了,盡管B.a對象是一個還未創(chuàng)建完成的對象。
  • 此時將B放入Map并且從Map3中刪除。
  • 這時候B創(chuàng)建完成,A繼續(xù)執(zhí)行b的屬性填充可以拿到B對象,這樣A也完成了創(chuàng)建。
  • 此時將A對象放入Map并從Map2中刪除。

源碼步驟解析

  • SpringBoot項目啟動執(zhí)行到SpringApplication#run 中的refreshContext(context);,最終調用Spring容器的AbstractApplicationContext#refresh方法,開始初始化BeanFactory。
  • 在AbstractApplicationContext#refresh步驟中,執(zhí)行到AbstractApplicationContext#finishBeanFactoryInitialization方法,開始完成 Bean 工廠初始化。
  • 執(zhí)行到AbstracBeanFactory.preInstantiateSingletons(),開始根據(jù)BeanFactory中的BeanDefinition信息初始化Bean對象。
  • 在AbstracBeanFactory.preInstantiateSingletons()方法中,發(fā)現(xiàn)A對象的BeanDefinition,執(zhí)行AbstracBeanFactory.getBean方法,獲取A對象。
  • 在AbstracBeanFactory.getBean方法中,執(zhí)行AbstracBeanFactory.doGetBean方法,獲取A對象。
  • 在AbstracBeanFactory.doGetBean方法中執(zhí)行DefaultSingletonBeanRegistry#getSingleton方法,嘗試從緩存中獲取A對象的單例對象緩存。
    • 到一級緩存singletonObjects中找,未找到;
    • 到二級緩存earlySingletonObjects中找,未找到;
    • 到三級緩存singletonFactories中找,未找到;
  • 再次執(zhí)行DefaultSingletonBeanRegistry#getSingleton的重載方法,傳入lamda表達式形式的ObjectFactory對象,內部調用AbstractAutowireCapableBeanFactory#createBean方法,嘗試創(chuàng)建A對象。
  • 在AbstractAutowireCapableBeanFactory#createBean方法中,調用AbstractAutowireCapableBeanFactory#doCreateBean方法,實際執(zhí)行創(chuàng)建A對象。
  • 實例化A對象,給字段賦值默認值后,調用DefaultSingletonBeanRegistry#addSingletonFactory方法,傳入A對象的lamda表達式形式的ObjectFactory對象,將ObjectFactory對象放入三級緩存singletonFactories中,并從2級緩存earlySingletonObjects中移除(雖然這里沒有),設置A對象已經(jīng)開始注冊。
    • 此處傳入的lamda表達式,內部調用了AbstractAutowireCapableBeanFactory#getEarlyBeanReference,此方法用來執(zhí)行實現(xiàn)了SmartInstantiationAwareBeanPostProcessor的后置處理器,比如實現(xiàn)AOP的AbstractAutoProxyCreator
  • 然后開始執(zhí)行A對象的AbstractAutowireCapableBeanFactory#populateBean,進行屬性填充。
  • 在進行屬性填充時,發(fā)現(xiàn)依賴了B對象,執(zhí)行AbstracBeanFactory.getBean方法,嘗試獲取B對象。參考上面步驟4~9。
  • 執(zhí)行到B對象的屬性填充時,發(fā)現(xiàn)依賴了A對象,執(zhí)行AbstracBeanFactory.getBean方法,嘗試獲取A對象。
  • 在AbstracBeanFactory.doGetBean方法中執(zhí)行DefaultSingletonBeanRegistry#getSingleton方法,嘗試從緩存中獲取A對象的單例對象緩存。
    • 到一級緩存singletonObjects中找,未找到;
    • 到二級緩存earlySingletonObjects中找,未找到;
    • 到三級緩存singletonFactories中找,找到了,并調用ObjectFactory的getObject方法獲取A對象的引用,ObjectFactory內部調用了AbstractAutowireCapableBeanFactory#getEarlyBeanReference,獲取到A的早期對象,將A的早期對象放入二級緩存earlySingletonObjects中,并將三級緩存singletonFactories中A對象移除;
  • 這樣拿到A的對象之后,B的屬性填充完畢,B初始化完成,方法return到DefaultSingletonBeanRegistry#getSingleton的重載方法時,調用DefaultSingletonBeanRegistry#addSingleton方法,將B對象放入一級緩存,并將B從二三級緩存中移除(雖然已經(jīng)沒有了)。
  • 這樣在return回A的流程,第11步,將A依賴的B屬性填充完整,此時A也填充完畢,初始化完成,方法繼續(xù)return到A流程的DefaultSingletonBeanRegistry#getSingleton的重載方法時,調用DefaultSingletonBeanRegistry#addSingleton方法,將A對象放入一級緩存,并將A從二三級緩存中移除(此時只有二級緩存中有)。
  • 這樣A和B就初始化完成了。
  • 如果A或者B存在AOP,需要返回代理對象,這操作是在第9步的AbstractAutowireCapableBeanFactory#getEarlyBeanReference中完成的,B嘗試獲取A的時候,觸發(fā)了這個方法,如果A需要被代理,則是在這個方法中執(zhí)行的,這個方法最終返回了一個代理對象,并將這個對象以A的名義放入了二級緩存。
  • 打完收工。

源碼

AbstractApplicationContext#refresh#finishBeanFactoryInitialization 入口類方法 刷新上下文,初始化BeanFactory,完成工廠初始化。
DefaultListableBeanFactory#preInstantiateSingletons 準備實例化單例對象

    @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對象

    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

AbstractBeanFactory#doGetBean 實際執(zhí)行獲取bean對象

    /**
     * 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 三級緩存

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

    /** Cache of singleton objects: bean name to bean instance. 一級緩存 */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** Cache of singleton factories: bean name to ObjectFactory. 三級緩存 */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** Cache of early singleton objects: bean name to bean instance. 二級緩存 */
    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;
    }
}

到此這篇關于Spring三級緩存解決循環(huán)依賴 的文章就介紹到這了,更多相關Spring 循環(huán)依賴內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java實現(xiàn)螺旋矩陣的示例

    Java實現(xiàn)螺旋矩陣的示例

    這篇文章主要介紹了Java實現(xiàn)螺旋矩陣的示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • IDEA2022中部署Tomcat Web項目的流程分析

    IDEA2022中部署Tomcat Web項目的流程分析

    這篇文章主要介紹了IDEA2022中部署Tomcat Web項目,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • Java矩陣連乘問題(動態(tài)規(guī)劃)算法實例分析

    Java矩陣連乘問題(動態(tài)規(guī)劃)算法實例分析

    這篇文章主要介紹了Java矩陣連乘問題(動態(tài)規(guī)劃)算法,結合實例形式分析了java實現(xiàn)矩陣連乘的算法原理與相關實現(xiàn)技巧,需要的朋友可以參考下
    2017-11-11
  • Java大數(shù)據(jù)處理的核心技術MapReduce框架

    Java大數(shù)據(jù)處理的核心技術MapReduce框架

    MapReduce是一種分布式計算框架,適用于大規(guī)模的數(shù)據(jù)處理。它將大數(shù)據(jù)分成多個小數(shù)據(jù)塊,通過Map和Reduce兩個階段對數(shù)據(jù)進行處理和分析。MapReduce框架具有可靠、高效、可擴展等特點,已經(jīng)成為大數(shù)據(jù)處理的核心技術
    2023-05-05
  • Maven如何構建可執(zhí)行的jar包(包含依賴jar包)

    Maven如何構建可執(zhí)行的jar包(包含依賴jar包)

    這篇文章主要介紹了Maven如何構建可執(zhí)行的jar包(包含依賴jar包) ,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • 解析Tomcat 6、7在EL表達式解析時存在的一個Bug

    解析Tomcat 6、7在EL表達式解析時存在的一個Bug

    這篇文章主要是對Tomcat 6、7在EL表達式解析時存在的一個Bug進行了詳細的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-12-12
  • Java實現(xiàn)屏幕截圖工具的代碼分享

    Java實現(xiàn)屏幕截圖工具的代碼分享

    這篇文章主要為大家介紹了如何利用Java語言編寫一個電腦屏幕截圖工具,文中的示例代碼講解詳細,對我們學習有一定的幫助,需要的可以參考一下
    2022-05-05
  • 詳解Spring Boot使用系統(tǒng)參數(shù)表提升系統(tǒng)的靈活性

    詳解Spring Boot使用系統(tǒng)參數(shù)表提升系統(tǒng)的靈活性

    Spring Boot項目中常有一些相對穩(wěn)定的參數(shù)設置項,其作用范圍是系統(tǒng)級的或模塊級的,這些參數(shù)稱為系統(tǒng)參數(shù)。這些變量以參數(shù)形式進行配置,從而提高變動和擴展的靈活性,保持代碼的穩(wěn)定性
    2021-06-06
  • Java實現(xiàn)鏈表中元素的獲取、查詢和修改方法詳解

    Java實現(xiàn)鏈表中元素的獲取、查詢和修改方法詳解

    這篇文章主要介紹了Java實現(xiàn)鏈表中元素的獲取、查詢和修改方法,結合實例形式詳細分析了Java針對鏈表中元素的獲取、查詢和修改相關原理、實現(xiàn)方法及操作注意事項,需要的朋友可以參考下
    2020-03-03
  • 詳解Java中的靜態(tài)代理模式

    詳解Java中的靜態(tài)代理模式

    這篇文章主要為大家介紹了Java中的靜態(tài)代理模式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2022-12-12

最新評論