返回顶部
首页 > 资讯 > 后端开发 > Python >Spring三级缓存解决循环依赖
  • 284
分享到

Spring三级缓存解决循环依赖

2024-04-02 19:04:59 284人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录一级缓存为什么不能在实例化A之后就放入Map?二级缓存 二级缓存已然解决了循环依赖问题,为什么还需要三级缓存?三级缓存 源码 我们都知道spring中的BeanFactory是一

我们都知道spring中的BeanFactory是一个ioc容器,负责创建Bean和缓存一些单例的Bean对象,以供项目运行过程中使用。

创建Bean的大概的过程:

  • 实例化Bean对象,为Bean对象在内存中分配空间,各属性赋值为默认值
  • 初始化Bean对象,为Bean对象填充属性
  • 将Bean放入缓存

首先,容器为了缓存这些单例的Bean需要一个数据结构来存储,比如Map {k:name; v:bean}。

而我们创建一个Bean就可以往Map中存入一个Bean。这时候我们仅需要一个Map就可以满足创建+缓存的需求。
但是创建Bean过程中可能会遇到循环依赖问题,比如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对象还没有创建,所以这里为了完成A的填充就必须要先去创建B对象;
  • 实例化B对象。
  • 执行到B对象的填充属性阶段,又会需要去获取A对象,而此时Map中没有A,因为A还没有创建完成,导致又需要去创建A对象。
  • 这样,就会循环往复,一直创建下去,只到堆栈溢出。

为什么不能在实例化A之后就放入Map?

因为此时A尚未创建完整,所有属性都是默认值,并不是一个完整的对象,在执行业务时可能会抛出未知的异常。所以必须要在A创建完成之后才能放入Map。

二级缓存

此时我们引入二级缓存用另外一个Map2 {k:name; v:earlybean} 来存储尚未已经开始创建但是尚未完整创建的对象。

  • 实例化A对象之后,将A对象放入Map2中。
  • 在填充A的属性阶段需要去填充B对象,而此时B对象还没有创建,所以这里为了完成A的填充就必须要先去创建B对象。
  • 创建B对象的过程中,实例化B对象之后,将B对象放入Map2中。
  • 执行到B对象填充属性阶段,又会需要去获取A对象,而此时Map中没有A,因为A还没有创建完成,但是我们继续从Map2中拿到尚未创建完毕的A的引用赋值给a字段。这样B对象其实就已经创建完整了,尽管B.a对象是一个还未创建完成的对象。
  • 此时将B放入Map并且从Map2中删除。
  • 这时候B创建完成,A继续执行b的属性填充可以拿到B对象,这样A也完成了创建。
  • 此时将A对象放入Map并从Map2中删除。

二级缓存已然解决了循环依赖问题,为什么还需要三级缓存?

从上面的流程中我们可以看到使用两级缓存可以完美解决循环依赖的问题,但是Spring中还有另外一个问题需要解决,这就是初始化过程中的aop实现。

AOP是Spring的重要功能,实现方式就是使用代理模式动态增强类的功能。

动态单例目前有两种技术可以实现,一种是jdk自带的基于接口的动态Proxy技术,一种是CGlib基于字节码动态生成的Proxy技术,这两种技术都是需要原始对象创建完毕,之后基于原始对象生成代理对象的。

那么我们发现,在二级缓存的设计下,我们需要在放入缓存Map之前将代理对象生成好。
将流程改为:

  • 实例化Bean对象,为Bean对象在内存中分配空间,各属性赋值为默认值
  • 如果有动态单例,生成Bean对象的代理Proxy对象
  • 初始化Proxy对象,为Bean对象填充属性
  • 将Proxy放入缓存

这样虽然也可以解决,AOP的问题,但是我们知道Spring中AOP的实现是通过后置处理器BeanPostProcessor机制来实现的,而后置处理器是在填充属性结束后才执行的。流程如下:

  • 实例化对象
  • 对象填充属性
  • BeanPostProcessor doBefore
  • init-method
  • BeanPostProcessor doAfter -- AOP是在这个阶段实现的

所以要实现上面的方案,势必需要将BeanPostProcessor阶段提前或者侵入到填充属性的流程中,那么从程序设计上来说,这样做肯定是不美的。

三级缓存

Spring引入了第三级缓存来解决这个问题, Map3 {k:name v:ObjectFactory} ,这个缓存的value就不是Bean对象了,而是一个接口对象由一段lamda表达式实现。在这段lamda表达式中去完成一些BeanPostProcessor的执行。

  • 实例化A对象之后,将A的ObjectFactory对象放入Map3中。
  • 在填充A的属性阶段需要去填充B对象,而此时B对象还没有创建,所以这里为了完成A的填充就必须要先去创建B对象。
  • 创建B对象的过程中,实例化B的ObjectFactory对象之后,将B对象放入Map2中。
  • 执行到B对象填充属性阶段,又会需要去获取A对象,而此时Map1中没有A,因为A还没有创建完成,但是我们继续从Map2中也拿不到,到Map3中获取了A的ObjectFactory对象,通过ObjectFactory对象获取A的早期对象,并将这个早期对象放入Map2中,同时删除Map3中的A,将尚未创建完毕的A的引用赋值给a字段。这样B对象其实就已经创建完整了,尽管B.a对象是一个还未创建完成的对象。
  • 此时将B放入Map并且从Map3中删除。
  • 这时候B创建完成,A继续执行b的属性填充可以拿到B对象,这样A也完成了创建。
  • 此时将A对象放入Map并从Map2中删除。

源码步骤解析

  • SpringBoot项目启动执行到SpringApplication#run 中的refreshContext(context);,最终调用Spring容器的AbstractApplicationContext#refresh方法,开始初始化BeanFactory。
  • 在AbstractApplicationContext#refresh步骤中,执行到AbstractApplicationContext#finishBeanFactoryInitialization方法,开始完成 Bean 工厂初始化。
  • 执行到AbstracBeanFactory.preInstantiateSingletons(),开始根据BeanFactory中的BeanDefinition信息初始化Bean对象。
  • 在AbstracBeanFactory.preInstantiateSingletons()方法中,发现A对象的BeanDefinition,执行AbstracBeanFactory.getBean方法,获取A对象。
  • 在AbstracBeanFactory.getBean方法中,执行AbstracBeanFactory.doGetBean方法,获取A对象。
  • 在AbstracBeanFactory.doGetBean方法中执行DefaultSingletonBeanReGIStry#getSingleton方法,尝试从缓存中获取A对象的单例对象缓存。
    • 到一级缓存singletonObjects中找,未找到;
    • 到二级缓存earlySingletonObjects中找,未找到;
    • 到三级缓存singletonFactories中找,未找到;
  • 再次执行DefaultSingletonBeanRegistry#getSingleton的重载方法,传入lamda表达式形式的ObjectFactory对象,内部调用AbstractAutowireCapableBeanFactory#createBean方法,尝试创建A对象。
  • 在AbstractAutowireCapableBeanFactory#createBean方法中,调用AbstractAutowireCapableBeanFactory#doCreateBean方法,实际执行创建A对象。
  • 实例化A对象,给字段赋值默认值后,调用DefaultSingletonBeanRegistry#addSingletonFactory方法,传入A对象的lamda表达式形式的ObjectFactory对象,将ObjectFactory对象放入三级缓存singletonFactories中,并从2级缓存earlySingletonObjects中移除(虽然这里没有),设置A对象已经开始注册。
    • 此处传入的lamda表达式,内部调用了AbstractAutowireCapableBeanFactory#getEarlyBeanReference,此方法用来执行实现了SmartInstantiationAwareBeanPostProcessor的后置处理器,比如实现AOP的AbstractAutoProxyCreator
  • 然后开始执行A对象的AbstractAutowireCapableBeanFactory#populateBean,进行属性填充。
  • 在进行属性填充时,发现依赖了B对象,执行AbstracBeanFactory.getBean方法,尝试获取B对象。参考上面步骤4~9。
  • 执行到B对象的属性填充时,发现依赖了A对象,执行AbstracBeanFactory.getBean方法,尝试获取A对象。
  • 在AbstracBeanFactory.doGetBean方法中执行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从二三级缓存中移除(虽然已经没有了)。
  • 这样在return回A的流程,第11步,将A依赖的B属性填充完整,此时A也填充完毕,初始化完成,方法继续return到A流程的DefaultSingletonBeanRegistry#getSingleton的重载方法时,调用DefaultSingletonBeanRegistry#addSingleton方法,将A对象放入一级缓存,并将A从二三级缓存中移除(此时只有二级缓存中有)。
  • 这样A和B就初始化完成了。
  • 如果A或者B存在AOP,需要返回代理对象,这操作是在第9步的AbstractAutowireCapableBeanFactory#getEarlyBeanReference中完成的,B尝试获取A的时候,触发了这个方法,如果A需要被代理,则是在这个方法中执行的,这个方法最终返回了一个代理对象,并将这个对象以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 实际执行获取bean对象


    
    @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 {

    
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

    ...

    
    @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三级缓存解决循环依赖 的文章就介绍到这了,更多相关Spring 循环依赖内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Spring三级缓存解决循环依赖

本文链接: https://lsjlt.com/news/160733.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Spring三级缓存解决循环依赖
    目录一级缓存为什么不能在实例化A之后就放入Map?二级缓存 二级缓存已然解决了循环依赖问题,为什么还需要三级缓存?三级缓存 源码 我们都知道Spring中的BeanFactory是一...
    99+
    2024-04-02
  • Spring解决循环依赖的方法(三级缓存)
      说起Spring,作为流水线上装配工的小码农,可能是我们最熟悉不过的一种技术框架。但是对于Spring到底是个什么东西,我猜作为大多数的你可能跟我一样,只知道IOC、DI,却并不...
    99+
    2024-04-02
  • Spring使用三级缓存解决循环依赖的问题
    Spring如何使用三级缓存解决循环依赖在没开始文章之前首先来了解一下什么是循环依赖 @Component public class A { @Autowired ...
    99+
    2024-04-02
  • Spring为什么需要三级缓存解决循环依赖
    今天小编给大家分享一下Spring为什么需要三级缓存解决循环依赖的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。bean生命周...
    99+
    2023-06-29
  • Spring三级缓存解决循环依赖的过程分析
    目录循环依赖解决思路解决流程二个缓存不行?总结循环依赖 什么是循环依赖?很简单,看下方的代码就知晓了 @Service public class A { @Autowired...
    99+
    2023-05-14
    Spring循环依赖 Spring三级缓存解决循环依赖
  • Spring为何需要三级缓存解决循环依赖详解
    目录前言bean生命周期三级缓存解决循环依赖总结前言 在使用spring框架的日常开发中,bean之间的循环依赖太频繁了,spring已经帮我们去解决循环依赖问题,对我们开发者来说是...
    99+
    2024-04-02
  • 教你Spring如何使用三级缓存解决循环依赖
    一级缓存存放实例化对象 。二级缓存存放已经在内存空间创建好但是还没有给属性赋值的对象。三级缓存存放对象工厂,用来创建提前暴露到bean的对象。 @Service public cla...
    99+
    2024-04-02
  • Spring解决循环依赖问题及三级缓存的作用
    目录前言1什么是循环依赖2 如何解决循环依赖3无法解决的循环依赖前言 所谓的三级缓存只是三个可以当作是全局变量的Map,Spring的源码中大量使用了这种先将数据放入容器中等使用结束...
    99+
    2024-04-02
  • 怎么使用Spring三级缓存解决循环依赖问题
    这篇文章主要介绍了怎么使用Spring三级缓存解决循环依赖问题的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么使用Spring三级缓存解决循环依赖问题文章都会有所收获,下面我们一起来看看吧。循环依赖什么是循环...
    99+
    2023-07-05
  • Spring源码之循环依赖之三级缓存详解
    目录循环依赖定义三种循环依赖的情况1.构造器循环依赖2.settler循环依赖3.prototype范围的依赖处理三级缓存机制整体分析源码分析面试题总结循环依赖 定义 循环依赖就 循...
    99+
    2024-04-02
  • 你知道怎么用Spring的三级缓存解决循环依赖吗
    目录1. 前言2. Spring Bean的循环依赖3. Spring中三大循环依赖场景演示3.1 构造器注入循环依赖3.2 singleton模式field属性注入循环依...
    99+
    2024-04-02
  • Spring解决循环依赖问题及三级缓存的作用是什么
    本文小编为大家详细介绍“Spring解决循环依赖问题及三级缓存的作用是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring解决循环依赖问题及三级缓存的作用是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知...
    99+
    2023-07-02
  • 关于Java Spring三级缓存和循环依赖的深入理解
    目录一、什么是循环依赖?什么是三级缓存?二、三级缓存如何解决循环依赖?三、使用二级缓存能不能解决循环依赖?一、什么是循环依赖?什么是三级缓存? 【什么是循环依赖】什么是循环依赖很好理...
    99+
    2024-04-02
  • 一篇文章带你理解Java Spring三级缓存和循环依赖
    目录一、什么是循环依赖?什么是三级缓存二、三级缓存如何解决循环依赖?三、使用二级缓存能不能解决循环依赖?总结一、什么是循环依赖?什么是三级缓存 【什么是循环依赖】什么是循环依赖很好理...
    99+
    2024-04-02
  • Spring怎么解决循环依赖
    本篇内容介绍了“Spring怎么解决循环依赖”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!写在前面最近,在...
    99+
    2024-04-02
  • Spring轻松解决循环依赖
    目录解决循环依赖的原理源码解析总结Spring 框架是一个流行的Java应用程序框架,它提供了许多强大的功能,如依赖注入和面向切面编程。然而在使用 Spring 框架时,我们可能会遇...
    99+
    2023-05-16
    Spring循环依赖怎么解决 Spring循环依赖
  • 浅谈Spring解决循环依赖的三种方式
    引言:循环依赖就是N个类中循环嵌套引用,如果在日常开发中我们用new 对象的方式发生这种循环依赖的话程序会在运行时一直循环调用,直至内存溢出报错。下面说一下Spring是如果解决循环依赖的。第一种:构造器参数循环依赖表示通过构造器注入构成的...
    99+
    2023-05-30
    spring 循环 依赖
  • spring中如何解决循环依赖
    这期内容当中小编将会给大家带来有关spring中如何解决循环依赖,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1.由同事抛的一个问题开始我们先看看当时出问题的代码片段:@...
    99+
    2024-04-02
  • Spring循环依赖的解决方法
    这篇文章主要介绍Spring循环依赖的解决方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!循环依赖其实就是循环引用,很多地方都说需要两个或则两个以上的bean互相持有对方最终形成闭环才是循环依赖,比如A依赖于B,B...
    99+
    2023-06-06
  • Spring循环依赖产生与解决
    目录循环依赖产生情景Spring如何解决循环依赖循环依赖产生情景 探讨如何解决循环依赖之前,更应该思考清楚什么情况下会发生这种问题? 1、模拟Prototype Bean的循环依赖 ...
    99+
    2022-12-20
    Spring如何解决循环依赖 Spring循环依赖
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作