Spring为什么需要三级缓存解决循环依赖?二级缓存不行的吗?

2021-12-20 00:00:00 缓存 依赖 二级缓存

Spring中如何创建循环依赖的?
    1、依赖的 Bean 必须都是单例
    2、依赖注入的方式,必须不全是构造器注入,且 beanName 字母序在前的不能是构造器注入
    
为什么都必须是单例的?
从源码来看 循环依赖的Bean是原型模式(原型模式(Prototype Pattern)是用于创建重复的对象,
        同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。)直接会产生错误的。
        
Spring只支持单例模式。为什么?
    若Bean是两个原型模式的话,则会有以下的出现
        那么创建 A1 需要创建一个 B1。
        创建 B1 的时候要创建一个 A2。
        创建 A2 又要创建一个 B2。
        创建 B2 又要创建一个 A3。
        创建 A3 又要创建一个 B3…..
        卡 BUG 了,因为原型模式都需要创建新的对象,不能跟用以前的对象。
        
    spring操作的时候是基于单例的模式
        先创建A,此时的A并不完整(没有注入B),用map去保存不完整的A,再创建B,B需要A
        map得到不完整的A,B此时就完整,A就可以直接的注入B。则B就完整。相互依赖。
        
为什么不能够全是构造器注入的?
    在spring中创建Bean分三步走:
        实例化
        属性注入
        初始化
    
    如果全都是构造器注入的话,还是一样,两个类AB
    使用构造器注入的话,会出现这种情况
        如果全是构造器注入,比如A(B b),那表明在 new 的时候,就需要得到 B,此时需要 new B 。
        但是 B 也是要在构造的时候注入 A ,即B(A a),这时候 B 需要在一个 map 中找到不完整的 A ,发现找不到
        若全是构造器注入的话,spring则无法进行解决循环依赖的问题啦
        
        
    一个set注入,一个构造器注入的话,一定可以成功的吗?
        假设我们 A 是通过 set 注入 B,B 通过构造函数注入 A,此时是成功的。
        实例化 A 之后,可以在 map 中存入 A,开始为 A 进行属性注入,发现需要 B。
        此时 new B,发现构造器需要 A,此时从 map 中得到 A ,B 构造完毕。
        B 进行属性注入,初始化,然后 A 注入 B 完成属性注入,然后初始化 A。
        
        但是假若A是通过构造器注入B的,B通过set注入A的 ,会失败的
            实例化A,发现构造函数需要B,去实例化B,B的属性注入,在Map中找不到A,A还没有new成功,B卡主
            
        
        
根据此,解决循环依赖的全过程。
    Spring创建Bean的三个步骤
        为单实例创建的三个map
            1、一级缓存:singletonObjects,存储所有已经完成的单例Bean
            2、二级缓存:earlySingletonObjects,存储所有仅完成实例化、但是还未进行属性注入的和初始化的Bean
            3、三级缓存:singletonFatories,存储能够简历这个Bean的一个工厂,通过工厂来获取这个Bean,延迟化Bean的生成
                工厂会生成Bean会塞入二级缓存
    这三个 map 是如何配合的呢?
        1、首先,获取单例 Bean 的时候会通过 BeanName 先去 singletonObjects(一级缓存) 查找完整的 Bean,如果找到则直接返回,否则进行步骤 2。
        2、看对应的 Bean 是否在创建中,如果不在直接返回找不到,如果是,则会去 earlySingletonObjects (二级缓存)查找 Bean,如果找到则返回,否则进行步骤 3
        3、去 singletonFactories (三级缓存)通过 BeanName 查找到对应的工厂,如果存着工厂则通过工厂创建 Bean ,并且放置到 earlySingletonObjects 中。
        4、如果三个缓存都没找到,则返回 null
        
为什么解决循环依赖需要三级缓存,二级不够的吗?
    若仅仅是为了破解循环依赖的话,二级缓存就够,因为在实例化 Bean A 之后,我在二级 map 里面塞入这个 A,然后继续属性注入。
        发现 A 依赖 B 所以要创建 Bean B,这时候 B 就能从二级 map 得到 A ,完成 B 的建立之后, A 自然而然能完成。        
        
    为什么要弄一个三级的缓存?存放的是Bean的工厂的啦?
        protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
            Object exposedObject = bean;
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                for (SmartInstantiationAwareBeanPostProcessor bp ://若为真,则说明有Bean的aop代理, getBeanPostProcessorCache().smartInstantiationAware) {
                    exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
            return exposedObject;
        }
    这个工厂的作用就是判断这个对象是否需要代理,如果否则直接返回,如果是则返回代理对象。
    
    正常的代理的对象初始化后期调用生成的,是基于后置处理器的,若提早的代理就违背了Bean定义的生命周期。
    所以spring在一个三级缓存放置一个工厂,如果产生循环依赖 ,那么就会调用这个工厂提早的得到代理的对象。
   至此     
        
        

    原文作者:努力撸代码的小刑
    原文地址: https://blog.csdn.net/weixin_40701758/article/details/123569043
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。

相关文章