前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【彻底搞懂】Spring之三级缓存解决循环依赖问题

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

作者头像
西柚dzh
发布2022-06-09 17:33:09
3.3K2
发布2022-06-09 17:33:09
举报
文章被收录于专栏:dcmickey小站dcmickey小站

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
复制
refresh();

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

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

代码语言:javascript
复制
@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
复制
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();

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

代码语言:javascript
复制
// 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
复制
@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}
代码语言:javascript
复制
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
复制
@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
复制
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
复制
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
复制
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
复制
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
复制
populateBean(beanName, mbd, instanceWrapper);

populateBean中的核心代码

代码语言:javascript
复制
// populateBean中的核心代码
applyPropertyValues(beanName, mbd, bw, pvs);

applyPropertyValues核心代码

代码语言:javascript
复制
// applyPropertyValues核心代码
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);

resolveValueIfNecessary核心代码

代码语言:javascript
复制
return resolveReference(argName, ref);

resolveReference核心代码

代码语言:javascript
复制
bean = this.beanFactory.getBean(resolvedName);

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

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

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

代码语言:javascript
复制
@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
复制
Object earlySingletonReference = getSingleton(beanName, false);

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

代码语言:javascript
复制
if (newSingleton) {
   addSingleton(beanName, singletonObject);
}

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

代码语言:javascript
复制
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
复制
if (earlySingletonExposure) {
    Object earlySingletonReference = getSingleton(beanName, false);
    if (earlySingletonReference != null) {
        if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
        }
        ..............
    }
}

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

代码语言:javascript
复制
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 删除。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Spring之三级缓存解决循环依赖问题
    • 前言
      • 场景
        • 三级缓存是什么
          • 对象创建步骤白话版
            • 疑问?
              • 为什么构造器方式不能解决循环依赖问题
              • 二级缓存能解决循环依赖吗,为什么要三级缓存
            • 对象创建步骤详尽版
              • 1.我们从Spring上下文入手AnnotationConfigApplicationContext,进去有一个非常重要的方法
              • 2.refresh方法上面是一堆准备过程,重点是finishBeanFactoryInitialization(beanFactory);方法
              • 3.执行beanFactory.preInstantiateSingletons();
              • 4.循环判断是否是单例非懒加载的bean,然后调用getBean(beanName);
              • 5.【非常重要】==getSingleton(beanName);== 实现逻辑
              • 6.返回到第四步的方法中,往下执行else,再次调用重载的getSingleton方法
              • 7.执行doCreateBean
              • 8.基于上面的源码,可以看到通过addSingletonFactory将对象A写入三级缓存singletonFactories中
              • 9.继续执行doCreateBean中下边的代码,此时开始填充A对象的属性。
              • 10.初始化对象B,此时B开始重复刚刚A的一套流程
              • 11.对象B开始填充属性
              • 12.此时的现象是对象A跑到二级缓存,对象B即将完成初始化动作
              • 13.对象B回到doCreateBean方法中,一路执行直到B创建过程全部完成
              • 14.B对象有了之后,执行到getSingleton方法的最下面addSingleton方法
              • 15.B对象放到一级缓存中,删除三级缓存和二级缓存,B对象标记注册完成
              • 16.B完成后,此时回到了第10步,对象A的属性B已经创建完毕拿到来,对象A初始化也全部执行完,继续向下执行
              • 17.对象A也回到getSingleton方法中,同14步
              • 18.对象A终于放到一级缓存,删除三级缓存
              • 19.到此为止 A和B都放入了一级缓存。完成循环依赖注入的问题!!!
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档