Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【彻底搞懂】Spring之三级缓存解决循环依赖问题

【彻底搞懂】Spring之三级缓存解决循环依赖问题

作者头像
西柚dzh
发布于 2022-06-09 09:33:09
发布于 2022-06-09 09:33:09
3.8K20
代码可运行
举报
文章被收录于专栏:dcmickey小站dcmickey小站
运行总次数:0
代码可运行

Spring之三级缓存解决循环依赖问题

著作权归作者所有。 商业转载请联系作者获得授权,非商业转载请注明出处。 作者:西柚dzh 链接:https://cloud.tencent.com/developer/article/2019359 来源:https://www.dcmickey.cn/

前言

本文是以源码断点方式提取出核心方法点,方便大家理解以及调试时不走弯路。

整个Bean的创建过程相当复杂,并且容易绕脑子。最好还是结合源码来看

有机会画点图,文字太多了

场景

A引用B ,B引用A。

Spring如何帮我们创建A和B对象

三级缓存是什么

  • singletonObjects, 一级缓存
  • earlySingletonObjects, 二级缓存
  • singletonFactories 三级缓存

缓存其实就是三个Map

对象创建步骤白话版

想看整个spring源码核心方法的过程的请看本文最下方<对象创建步骤详尽版>

  1. 对象A要创建到Spring容器中,从一级缓存singletonObject获取A,不存在,开始实例化A,最终在三级缓存singletonObjectFactory添加(A,A的函数式接口创建方法),这时候A有了自己的内存地址
  2. 设置属性B,B也从一级缓存singletonObject获取B,不存在,开始实例化B,最终在三级缓存singletonObjectFactory添加(B,B的函数式接口创建方法),这时候B有了自己的内存地址
  3. B中开始给属性A赋值,此时会找到三级缓存中的A,并将A放入二级缓存中。删除三级缓存
  4. B初始化完成,从三级缓存singletonObjectFactory直接put到一级缓存singletonObject,并删除二级和三级缓存的自己
  5. A成功得到B,A完成初始化动作,从二级缓存中移入一级缓存,并删除二级和三级缓存的自己
  6. 最终A和B都进入一级缓存中待用户使用

疑问?

为什么构造器方式不能解决循环依赖问题

spring解决循环依赖是通过对象的实例化和初始化分开的步骤来实现的,如果是构造函数注入的话,对象实例化就卡住了

实例化时申请出对象的空间,初始化给对象填充属性

二级缓存能解决循环依赖吗,为什么要三级缓存

思考为啥要在三级缓存中方函数式接口创建方法(匿名内部类)?

在于为了创建代理对象,三级缓存中放入的是生成该对象的一个匿名内部类,可能是生成代理类,也可能是普通对象。

以下摘自网络博客 Spring 为何需要三级缓存解决循环依赖,而不是二级缓存 我们会发现再执行一遍singleFactory.getObject()方法又是一个新的代理对象,这就会有问题了,因为AService是单例的,每次执行singleFactory.getObject()方法又会产生新的代理对象,假设这里只有一级和三级缓存的话,我每次从三级缓存中拿到singleFactory对象,执行getObject()方法又会产生新的代理对象,这是不行的,因为AService是单例的,所有这里我们要借助二级缓存来解决这个问题,将执行了singleFactory.getObject()产生的对象放到二级缓存中去,后面去二级缓存中拿,没必要再执行一遍singletonFactory.getObject()方法再产生一个新的代理对象,保证始终只有一个代理对象。还有一个注意的点 既然singleFactory.getObject()返回的是代理对象,那么注入的也应该是代理对象,我们可以看到注入的确实是经过CGLIB代理的AService对象。所以如果没有AOP的话确实可以两级缓存就可以解决循环依赖的问题,如果加上AOP,两级缓存是无法解决的,不可能每次执行singleFactory.getObject()方法都给我产生一个新的代理对象,所以还要借助另外一个缓存来保存产生的代理对象

对象创建步骤详尽版

1.我们从Spring上下文入手AnnotationConfigApplicationContext,进去有一个非常重要的方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
refresh();

2.refresh方法上面是一堆准备过程,重点是finishBeanFactoryInitialization(beanFactory);方法

// Instantiate all remaining (non-lazy-init) singletons. 完成所有单例非懒加载的对象实例化

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        ....
        try {
            .....
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);
            // Last step: publish corresponding event.
            finishRefresh();
        }
        catch (BeansException ex) {
            throw ex;
        }
        finally {
        }
    }
}

3.执行beanFactory.preInstantiateSingletons();

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();

4.循环判断是否是单例非懒加载的bean,然后调用getBean(beanName);

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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)) {
        }
        else {
            getBean(beanName);
        }
    }
}

// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
    Object singletonInstance = getSingleton(beanName);
    ......
}

具体实现者doGetBean(name, null, null, false);方法,调用getSingleton(beanName);

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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) {
        beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    else {
        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        ...
        // Create bean instance.
        if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
                try {
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    destroySingleton(beanName);
                    throw ex;
                }
            });
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }

    return adaptBeanInstance(name, beanInstance, requiredType);
}

5.【非常重要】==getSingleton(beanName);== 实现逻辑

1.从一级缓存singletonObjects获取对象A,发现不存在 2.对象不存在并且不在初始化中(isSingletonCurrentlyInCreation) 3.直接返回null出去

5.1仔细看,这里就用到了DCL的单例模式
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
@Nullable
public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}

@Nullable
protected Object getSingleton(Sjatring 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;
}

6.返回到第四步的方法中,往下执行else,再次调用重载的getSingleton方法

将一个函数式方法传递进去!!!! 记住这个!!!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
else {
        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        ...
        // Create bean instance.
        if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
                try {
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    destroySingleton(beanName);
                    throw ex;
                }
            });
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName,         mbd);
    }

在这次的getSingleton方法中 1.同样尝试从一级缓存中获取对象A,不存在 2.执行singletonFactory.getObject(); 也就是传进来的函数式方法createBean(beanName, mbd, args); 3.执行到了Object beanInstance = doCreateBean(beanName, mbdToUse, args);

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                .....
                try {
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                catch (IllegalStateException ex) {            
                }
                finally {
                    ...
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }

7.执行doCreateBean

这一步就实例化完成了,申请到了地址

1.执行到instanceWrapper = createBeanInstance(beanName, mbd, args); 2.instantiateBean(beanName, mbd); 3.beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this); 4.BeanUtils.instantiateClass(constructorToUse); 5.return ctor.newInstance(argsWithDefaultValues); 6.一直return到doCreateBean里,然后向下执行addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
   
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
   .....
    // 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) {
        ...
        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 (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;
}

8.基于上面的源码,可以看到通过addSingletonFactory将对象A写入三级缓存singletonFactories中

==但是存的只是一个函数式方法() -> getEarlyBeanReference(beanName, mbd, bean)==

1.判断一级缓存没有 2.写入三级缓存singletonFactories,并删除二级缓存 3.标记当前对象A注册了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
        }
    }
}

9.继续执行doCreateBean中下边的代码,此时开始填充A对象的属性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
populateBean(beanName, mbd, instanceWrapper);

populateBean中的核心代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// populateBean中的核心代码
applyPropertyValues(beanName, mbd, bw, pvs);

applyPropertyValues核心代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// applyPropertyValues核心代码
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);

resolveValueIfNecessary核心代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
return resolveReference(argName, ref);

resolveReference核心代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bean = this.beanFactory.getBean(resolvedName);

这时候已经开始走A那时候的getBean的一套流程了

10.初始化对象B,此时B开始重复刚刚A的一套流程

重复4到8的过程,将对象B和对象B的函数式方法一起写入三级缓存

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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;
}

11.对象B开始填充属性

和第9步对应,填充属性A,通过第5.1步的getSingletion获取对象A,但是这次走向不同,A的状态已经变为初始化过程中了,可以进入if条件 1.双重锁DCL,从一级缓存singletionObject中获取,不存在 2.从二级缓存earlySingletonObject中获取,不存在 3.上锁synchronize一级缓存 4.再次确认一级缓存和二级缓存中有没有 5.从三级缓存singletonFactories中取到了对象A 6.并且将对象A的匿名内部类给执行了,得到具体对象转移到二级缓存中去了,三级缓存移除掉A 7.将A对象地址给到B对象的A属性上,完成初始化动作 ​ bw.setPropertyValues(new MutablePropertyValues(deepCopy));

12.此时的现象是对象A跑到二级缓存,对象B即将完成初始化动作

并且这个二级缓存的A不是三级缓存的A,而是通过三级缓存存的那个方法执行后的对象

13.对象B回到doCreateBean方法中,一路执行直到B创建过程全部完成

这里注意下执行到getSingleton时,因为传的是false。所以里面方法执行不到,B对象也就不会从三级缓存到二级缓存中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Object earlySingletonReference = getSingleton(beanName, false);

14.B对象有了之后,执行到getSingleton方法的最下面addSingleton方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (newSingleton) {
   addSingleton(beanName, singletonObject);
}

15.B对象放到一级缓存中,删除三级缓存和二级缓存,B对象标记注册完成

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}

16.B完成后,此时回到了第10步,对象A的属性B已经创建完毕拿到来,对象A初始化也全部执行完,继续向下执行

这里getsingleton 会从二级缓存中得到对象A

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (earlySingletonExposure) {
    Object earlySingletonReference = getSingleton(beanName, false);
    if (earlySingletonReference != null) {
        if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
        }
        ..............
    }
}

17.对象A也回到getSingleton方法中,同14步

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (newSingleton) {
    addSingleton(beanName, singletonObject);
}

18.对象A终于放到一级缓存,删除三级缓存

19.到此为止 A和B都放入了一级缓存。完成循环依赖注入的问题!!!


版权属于:dingzhenhua

本文链接:https://cloud.tencent.com/developer/article/2019359

转载时须注明出处及本声明

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
2 条评论
热度
最新
作者你好,我一直有个疑问,在A创建完后开始进行初始化属性填充时,此时A是执行了doCreateBean(第七步)申请到了地址,但在B进行属性填充A时又将对象A的匿名内部类给执行了(第十一步),这个时候和一开始A自己申请的地址不应该是不一样的吗?
作者你好,我一直有个疑问,在A创建完后开始进行初始化属性填充时,此时A是执行了doCreateBean(第七步)申请到了地址,但在B进行属性填充A时又将对象A的匿名内部类给执行了(第十一步),这个时候和一开始A自己申请的地址不应该是不一样的吗?
11点赞举报
这个时候,得到的A是从三级缓存里面获取的一个Factory生成的,有可能一样(没有使用代理),也可能不一样(使用了代理) 三级缓存里面存的是前面暴露的时候传入的Lambda表达式() -> getEarlyBeanReference(beanName, mbd, bean),我是这样理解的,不知道有没有错
这个时候,得到的A是从三级缓存里面获取的一个Factory生成的,有可能一样(没有使用代理),也可能不一样(使用了代理) 三级缓存里面存的是前面暴露的时候传入的Lambda表达式() -&gt; getEarlyBeanReference(beanName, mbd, bean),我是这样理解的,不知道有没有错
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
spring解决循环依赖为什么要用三级缓存?
上面的例子中AService实例化时会调用构造方法 public AService(BService bService),该构造方法依赖于BService的实例。此时BService还没有实例化,需要调用构造方法public BService(AService aService)才能完成实例化,该构造方法巧合又需要AService的实例作为参数。由于AService和BService都没有提前实例化,在实例化过程中又相互依赖对方的实例作为参数,这样构成了一个死循环,所以最终都无法再实例化了。
苏三说技术
2020/10/15
1.2K2
spring解决循环依赖为什么要用三级缓存?
Spring三级缓存
在正式研究Spring如何解决循环依赖之前,不如我们就假设spring目前没有提供三级缓存来解决循环依赖,那么目前spring的getBean流程图就如下所示:
大忽悠爱学习
2022/06/12
6680
Spring三级缓存
spring如何使用三级缓存解决循环依赖
在日常开发中,Bean之间的循环依赖非常常见,Spring 已经帮我们做到使用无感知处理,那么 Spring 是如何实现的呢?
政采云前端团队
2023/12/12
4100
spring如何使用三级缓存解决循环依赖
Spring循环依赖与三级缓存
但即使有三级缓存也无法解决构造器的循环依赖, 对象无法正常实例化, 没有操作的空间
code-x
2023/03/30
6250
Spring 循环依赖及解决方式
获取一个 Bean 的操作从 getBean(String name) 开始主要步骤为
程序狗
2021/12/09
5610
Spring的循环依赖和三级缓存
(2)如果您不了解Spring Bean的声明周期,那么您可以看一下文章(Bean的生命周期_CBeann的博客-CSDN博客)或者百度其它文章,然后在回来看该文章,否则个人感觉应该看不懂
CBeann
2023/12/25
2320
Spring的循环依赖和三级缓存
Spring如何解决循环依赖的
就是我们有两个服务,A服务,B服务,然后我们在A里注入了B,然后在B里注入了A,这就是循环依赖了,这种情况如果我们不解决的话,那就会出现一个相互依赖注入的死循环。
名字是乱打的
2021/12/24
1.1K0
Spring如何解决循环依赖的
一文告诉你Spring是如何利用"三级缓存"巧妙解决Bean的循环依赖问题的【享学Spring】
循环依赖:就是N个类循环(嵌套)引用。 通俗的讲就是N个Bean互相引用对方,最终形成闭环。用一副经典的图示可以表示成这样(A、B、C都代表对象,虚线代表引用关系):
YourBatman
2019/09/03
53.1K12
一文告诉你Spring是如何利用"三级缓存"巧妙解决Bean的循环依赖问题的【享学Spring】
Spring系列三之Bean实例化流程
紧接着上文,Spring的Bean实例化发生在刷新IOC容器阶段的倒数第二步finishBeanFactoryInitialization(beanFactory),最终在该方法中调用DefaultListable.preInstantiateSingletons()方法实例化所有非懒加载的Bean实例,代码如下
用户9511949
2024/09/05
1690
Spring循环依赖三级缓存是否可以减少为二级缓存?
我们都知道Spring通过三级缓存来解决循环依赖的问题,那么是不是必须是三级缓存?二级缓存不能解决吗?
程序员白楠楠
2021/01/29
9470
透过源码,捋清楚循环依赖到底是如何解决的!
关于 Spring 循环依赖,松哥已经连着发了三篇文章了,本篇文章松哥从源码的角度来和小伙伴们捋一捋 Spring 循环依赖到底是如何解决了。如果没看过前面的文章建议先看一下,大家在面试中如果遇到循环依赖相关的问题,其实看前面三篇文章就可以答出来了,本文主要是从源码角度来验证一下我们前面文章所讲的内容是无误的。
江南一点雨
2023/09/09
2550
透过源码,捋清楚循环依赖到底是如何解决的!
spring源码分析之如何解决循环依赖
spring-ioc中循环依赖的问题,也算是高频的面试问题了,今天跟大家一起来总结一下spring-ioc中是如何解决循环依赖的,相信大家是可以从这篇文章中彻底理解spring容器如何帮我们解决循环依赖,为了更好的理解spring-ioc如何解决循环依赖,大家可以先简单的了解spring-ioc中bean实例化的整个时序图。
全栈程序员站长
2022/07/04
4470
spring源码分析之如何解决循环依赖
烂了大街的 Spring 循环依赖问题,你觉得自己会了吗
初学 Spring 的时候,我们就知道 IOC,控制反转么,它将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理,不需要我们手动去各种 new XXX。
海星
2020/09/09
7000
spring如何解决循环依赖
使用构造器注入构成循环依赖,这种方式无法进行解决,抛出了BeanCurrentlyInCreationException异常
科技新语
2024/08/16
1160
spring如何解决循环依赖
spring循环依赖到底怎么解决的_恋爱循环难吗
问:Spring如何解决循环依赖? 答:Spring通过提前曝光机制,利用三级缓存解决循环依赖(这原理还是挺简单的,参考:三级缓存、图解循环依赖原理) 再问:Spring通过提前曝光,直接曝光到二级缓存已经可以解决循环依赖问题了,为什么一定要三级缓存? 再细问:如果循环依赖的时候,所有类又都需要Spring AOP自动代理,那Spring如何提前曝光?曝光的是原始bean还是代理后的bean?
全栈程序员站长
2022/09/22
1.2K0
spring循环依赖到底怎么解决的_恋爱循环难吗
Spring篇之循环依赖
循环依赖就是多个Bean之间存在相互依赖,形成一个闭环,如下,PostService和UserService之间就存在相互依赖,这个依赖并不是方法 之间的依赖,而是Bean与Bean之间的依赖。
小四的技术之旅
2022/07/26
1.7K0
Spring篇之循环依赖
Spring5.0源码深度解析之Spring是如何利用三级缓存解决循环依赖的问题
Spring已经成为了开发项目的不可缺少的组件了,我们在平常开发项目中难免会遇到以下这些情况,比如说,我有A类和B类,两个业务类都注入到Spring容器里了,且双方都互相注入了,这个时候就会造成循环依赖的问题,相信之前有很多开发者遇到这样的问题吧,不过现在Spring底层已经通过三级缓存来解决了这个循环依赖的问题了。
黎明大大
2021/03/09
1.6K0
spring解决循环依赖
spring 单例对象的实例化、初始化过程是在doCreateBean中(之前仅仅是注册好了BeanDefenition), 大概分为三步:
leobhao
2022/06/28
5530
Spring如何通过三级缓存解决循环依赖
这个例子存在的问题:理论上spring创建A的时候依赖了B,然后spring就会去加载B,但是这个时候B又依赖了A,spring又去加载A,就会陷入一个死循环,但我们在实际使用spring的时候并没有出现这样的循环,这是因为spring设计之初就考虑了这个问题,那么spring是如何解决的呢?我们先要明确的是spring对循环依赖的处理有三种情况,分别为
诺浅
2020/08/19
1K0
Spring缓存 & 解决循环依赖 & BeanFactory,FactoryBean区别?
一级缓存singletonObjects是线程安全的ConcurrentHashMap。
用户9919783
2022/07/29
3550
相关推荐
spring解决循环依赖为什么要用三级缓存?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验