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

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:西柚dzh
链接:https://www.dcmickey.cn/Java/237.html
来源: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,进去有一个非常重要的方法

refresh();

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

// Instantiate all remaining (non-lazy-init) singletons.

完成所有单例非懒加载的对象实例化

@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();

// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();

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

// 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);

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}
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的单例模式

@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方法

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

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);

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));

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注册了。

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对象的属性。

populateBean(beanName, mbd, instanceWrapper);

populateBean中的核心代码

// populateBean中的核心代码
applyPropertyValues(beanName, mbd, bw, pvs);

applyPropertyValues核心代码

// applyPropertyValues核心代码
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);

resolveValueIfNecessary核心代码

return resolveReference(argName, ref);

resolveReference核心代码

bean = this.beanFactory.getBean(resolvedName);

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

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

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

@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对象也就不会从三级缓存到二级缓存中

Object earlySingletonReference = getSingleton(beanName, false);

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

if (newSingleton) {
   addSingleton(beanName, singletonObject);
}

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

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

if (earlySingletonExposure) {
    Object earlySingletonReference = getSingleton(beanName, false);
    if (earlySingletonReference != null) {
        if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
        }
        ..............
    }
}

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

if (newSingleton) {
    addSingleton(beanName, singletonObject);
}

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

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