Spring三级缓存是为了解决对象间的循环依赖问题。

A依赖B,B依赖A,这就是一个简单的循环依赖。

我们来先看看三级缓存的源码:

获取Bean的源码

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
        //1级缓存 用于存放 已经属性赋值 初始化后的 单列BEAN
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
        //2级缓存 用于存在已经实例化,还未做代理属性赋值操作的 单例
        private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
        //3级缓存 存储单例BEAN的工厂
        private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
        //已经注册的单例池里的beanName
        private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
        //正在创建中的beanName
        private final Set<String> singletonsCurrentlyInCreation =
                Collections.newSetFromMap(new ConcurrentHashMap<>(16));
        //缓存查找bean  如果1级没有,从2级获取,也没有,从3级创建放入2级
        protected Object getSingleton(String beanName, boolean allowEarlyReference) {
            Object singletonObject = this.singletonObjects.get(beanName); //1级
            if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
                synchronized (this.singletonObjects) {
                    singletonObject = this.earlySingletonObjects.get(beanName); //2级
                    if (singletonObject == null && allowEarlyReference) {
                        //3级缓存  在doCreateBean中创建了bean的实例后,封装ObjectFactory放入缓存的
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            //创建未赋值的bean
                            singletonObject = singletonFactory.getObject();
                            //放入到二级缓存
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            //从三级缓存删除
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
            return singletonObject;
        }   
    }

注意上面的getSingleton()方法

添加到1级缓存

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

添加到三级缓存

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
            synchronized (this.singletonObjects) {
                if (!this.singletonObjects.containsKey(beanName)) {
                    //一级缓存没有,放入三级缓存
                    this.singletonFactories.put(beanName, singletonFactory);
                    //从二级缓存删除,确保二级缓存没有该bean
                    this.earlySingletonObjects.remove(beanName);
                    this.registeredSingletons.add(beanName);
                }
            }
        }

创建Bean的源码

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    
    if (instanceWrapper == null) {
        //实例化对象
        instanceWrapper = this.createBeanInstance(beanName, mbd, args);
    }

    final Object bean = instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null;
    Class<?> beanType = instanceWrapper != null ? instanceWrapper.getWrappedClass() : null;
   
    //判断是否允许提前暴露对象,如果允许,则直接添加一个 ObjectFactory 到三级缓存
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        //添加三级缓存
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    //填充属性
    this.populateBean(beanName, mbd, instanceWrapper);
    //执行初始化方法,并创建代理
    exposedObject = initializeBean(beanName, exposedObject, mbd);
    return exposedObject;
}

通过这段代码,我们可以知道Spring 在实例化对象的之后,就会为其创建一个 Bean 工厂,并将此工厂加入到三级缓存中。

因此,Spring 一开始提前暴露的并不是实例化的 Bean,而是将 Bean 包装起来的 ObjectFactory。为什么要这么做呢?

这实际上涉及到 AOP,如果创建的 Bean是有代理的,那么注入的就应该是代理 Bean,而不是原始的 Bean。但是 Spring一开始并不知道 Bean是否会有循环依赖,通常情况下(没有循环依赖的情况下),Spring 都会在完成填充属性,并且执行完初始化方法之后再为其创建代理。但是,如果出现了循环依赖的话,Spring 就不得不为其提前创建代理对象,否则注入的就是一个原始对象,而不是代理对象。因此,这里就涉及到应该在哪里提前创建代理对象?

Spring 的做法就是在 ObjectFactory 中去提前创建代理对象。它会执行 getObject() 方法来获取到 Bean。实际上,它真正执行的方法如下:

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                // 如果需要代理,这里会返回代理对象;否则返回原始对象
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
    }
    return exposedObject;
}

因为提前进行了代理,避免对后面重复创建代理对象,会在 earlyProxyReferences 中记录已被代理的对象。

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
        implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // 记录已被代理的对象
        this.earlyProxyReferences.put(cacheKey, bean);
        return wrapIfNecessary(bean, beanName, cacheKey);
    }
}

我们回到获取bean的方法getSingleton()

//缓存查找bean  如果1级没有,从2级获取,也没有,从3级创建放入2级
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName); //1级
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName); //2级
            if (singletonObject == null && allowEarlyReference) {
                //3级缓存  在doCreateBean中创建了bean的实例后,封装ObjectFactory放入缓存的
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    //创建未赋值的bean
                    singletonObject = singletonFactory.getObject();
                    //放入到二级缓存
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    //从三级缓存删除
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

这里有个比较重要的点。

提前暴露的对象,对象实例化,但是没有进行属性填充,还没有初始化,是一个不完整的对象, 这个对象存放在二级缓存中,这个对象在三级缓存中十分重要,是解决循环依赖一个非常巧妙的地方。

让我们来分析一下“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情景。

  1. doCreateBean()初始化,由于还未创建,从一级缓存查不到,此时只是一个半成品(提前暴露的对象),放入三级缓存singletonFactories;
  2. A发现自己需要B对象,但是三级缓存中未发现B,创建B的半成品,放入singletonFactories;
  3. B发现自己需要A对象,从一级缓存singletonObjects和二级缓存earlySingletonObjects中未发现A,但是在三级缓存singletonFactories中发现A,将A放入二级缓存earlySingletonObjects,同时从三级缓存删除;
  4. 将A注入到对象B中;
  5. B完成属性填充,执行初始化方法,将自己放入第一级缓存中(此时B是一个完整的对象);
  6. A得到对象B,将B注入到A中;
  7. A完成属性填充,初始化,并放入到一级缓存中。

在创建过程中,都是从三级缓存(对象工程创建不完整对象),将提前暴露的对象放入到二级缓存,从二级缓存拿到后,完成初始化,放入一级缓存。

 

[elementor-template id=”6632″]

分类: 微服务

4 条评论

abeervinum.it · 2021年3月8日 下午11:49

This is a topic that’s close to my heart… Cheers! Exactly where
are your contact details though?

ar15.site · 2021年3月8日 上午1:30

Hey! Would you mind if I share your blog with my
twitter group? There’s a lot of people that I think would really enjoy your content.
Please let me know. Thanks

    liwei · 2021年3月8日 上午8:24

    Hey, 可以的,但我的博客多为网上资料整合!希望于你有帮忙,于你的朋友有帮助!
    Yes, but my blog is mostly for online data integration! Hope to help you and your friends!

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

蜀ICP备16001794号
© 2014 - 2024 linpxing.cn All right reserved.