Spring循环依赖

Bean的生命周期

Aservicece:
1、calss — beanDefinition

2、new Aservicece() 通过反射或者工厂去实例话一个对象,我们称为原始对象 // 原始对象—Aop–代理对象—放入到我们的Map中去

3、属性填充—填充Bservice bservice属性----->从单例池中找到bservice对应那个bean的对象—不能找到—>从Map中去找—创建Bservice

4、初始化

5、初始化后 执行BeanPostProcessor,进行Aop

Bservicece:
1、calss — beanDefinition

2、new Aservicece() 通过反射或者工厂去实例话一个对象,我们称为原始对象

3、属性填充—填充Aservice aservice属性

4、初始化

5、初始化后 执行BeanPostProcessor,进行Aop

真正的循环依赖:
当Aservice在创建的时候依赖Bservices && Bservice在创建的时候也依赖Aservice && 发现Aservice还正在创建中,那么此时才算是真正的出现了循环依赖。

1、出现循环依赖的主要原因:
①: Spring的生命周期太长了
②:Spring要在初始化后进行Aop.这两个原因是导致循环依赖出现的根本原因。

针对第一种原因解决方案:
   使用一个Map就能解决
第二种场景的模拟:   
    正常我们Aop是在第五步,也就是初始化后开始会调用我们的BeanPostProcessor执行后置处理器,进行Aop.
        但是如果这样做就会出现问题:
         我们在BService中给aservices属性赋值的时候,赋值的本来是一个我们刚new出来的原始对象,但是当在初始化后进行完Aop之后,就会生成一个代理对象出来。
         而且我们都知道将来我们一定是将我们的代理对象放到我们的单例池中去。那么这样做,就出现问题了。我们对Bservie的Aservice的属性赋值完成之后,Bservices走完自己的生命周期,然后Aservices的第二步也能完成,接着Aservices完成3 4 5步,自此Aservice的生命周期也走完了。那么此时单例池中放入的是Aservices的代理对象bean,却给Bservice对象的Aservice属性注入的是原始对象,这样,就出现了一个Aservice出现了两个不同的对象,冲突就出现了。
第二种场景的解决方案;
    面对这种情况 我们该怎么解决呢?? ?
    我们如果将Aop提前,是不是就能解决问题呢?
    那我们又在哪一步去对Aop提前呢?
        如果我们在实例化完了一个对象之后,用原始对象去进行Aop是不是能解决问题呢?
        如果我们在实例化完一个对象之后,也即是我们的第二步,开始进行Aop,然后将Aservice的代理对象放到我们的HzkMap【这个Map是我在这里假设的一个Map,不是我们的三级缓存或者耳机缓存】之中,然后再执行Aservice的Bservice属性赋值的时候,去单例池中找,发现单例池中没找到,然后在去创建Bservice,开始走Bservice的生命周期,接着走Bservice的第二步属性填充,此时也还是先从容器中找Aservice,发现没有,接着从Map中找,此时发现找到了。然后用Aservice的代理对象去对Bservice的Aservice属性赋值填充。这样就能解决属性注入的对象和放入单例池中的对象不一样的问题。

    这样貌似是没有任何问题,但是出现了其它问题,
       1) 我们一旦在第二步进行了Aop之后,我们还用不用在初始化后【第五步】在进行Aop。这个其实比较好判断,一旦我们在第二步进行了Aop,那么我就不需要在第五步进行了。
       2) 我们什么时候去进行Aop的提前操作呢?
            因为Aop是一个可有可无的过程,如果是在第二步去进行Aop,那么是没有什么问题,但是如果Aservice没有进行Aop,这样在第二步在去进行Aop就不对了,	我们就只有还在第五步进行Aop,所以我们需要去判断什么时候进行Aop提前非常重要。而不能一味的去将Aop提前。  
    
           当出现循环的场景时候,这时就需要Aop提前。
               1) 没出现循环依赖的时候,仍然是在第五步进行Aop
               2) 出现了循环依赖的时候,这时就需要将Aop提前

           问题是如何判断什么时候出现了循环依赖?
                 如果整两个Bean的生命周期有十二步的话,那我们到底在哪一步去判断出现了循环依赖最合适呢?

                  在第二个的第三步是最合适:前面所有的步骤都不好去判断
                        只有当我们在给Bservices的Aservices的属性赋值的时候,这时候再去判断出现循环依赖最合适。
            【注意】:如果在第二个的第三步判断出了需要循环依赖,然后进行Aop,创建出代理对象。那么Aop的前提是需要要有一个原始对象(Aservice)  ,那么如何将原始对象注入
            进去呢,此时就需要了=======三级缓存。 那么三级缓存里面存的是个什么东西呢,首先key是我们的bean的名字,value存的是一个lambda表达式,其实按照Spring的逻辑,
            在三级缓存中存放key为bean的名字,value为一个原始对象,就行了。但是会出现其它的原因,具体出现什么原因,先不做讨论。我们在这里就记得是放入的是一个lambda
            表达式。
            【切记】我们只是放入一个lambda表达式,但是并没有去执行         

             当我们在第二个的第三步 去执行属性注入的时候,并且出现了循环依赖   接着先去三级缓存中去找,去执行lambda表达式。然后进行Aop==生成代理对象

             那么怎么解决这个问题呢?
             此时我们的二级缓存就出现了========二级缓存,作用:存放我们三级缓存生成的代理对象。
             这样Cservice的属性Aservice属性注入值的时候,生成代理对象前,先去二级缓存中去找。===找不到===在去三级缓存中去找到lambda表达式====执行lambda表达式===aop对象====放到二级缓存中去。
            最后还要做一步  就是将lambda表达式从三级缓存中移除,为了防止有可能出现这个lambda表达式被执行多次,那么只有给移除去才放心。


            如果没有出现循环依赖 我们的三级缓存  二级缓存都是没有什么用。


  如果只是Aservice依赖BServcie 并且Bservice依赖Aservice 那么是没有问题的,但是,但是,如果有多个依赖,比如Aservice还依赖Cservice Cservice依赖Aservice,

  并且都进行了Aop,那么此时就出现了问题。
  这时候就出现了两个Aop的代理对象,如果三个 四个 五个呢。。。那就会出现了多个代理对象。并且是不一样的。




     




本来给Bsevies中的Aservices属性注入的是Aservices的原始对象 但是如果一旦在第五步进行Aop之后,Aservicecs将会生成一个代理对象,并且将这个代理对象放到单例池中去,那么这时就会出现冲突。

那出现这个问题该怎么解决呢?
我们在创建完实例对象之后,就开始进行Aop,然后将	

什么时候进行Aop提前?
条件:当出现了循环依赖 则将Aop提前

正常情况下 使用两个map就能解决循环依赖 那为什么要用三级缓存来解决?

问题出现在第五步:Aop环节【如果要进行Aop】
本来给Bsevies中的Aservices属性注入的是Aservices的原始对象 但是如果一旦在第五步进行Aop之后,Aservicecs将会生成一个代理对象,并且将这个代理对象放到单例池中去,那么这时就会出现冲突
注入的是原始对象 放到单例池的是代理对象。
那么怎么解决呢?
此时仍然不需要三级缓存,两个map仍然能够解决。
我们在第二步创建完一个原始对象之后,开始进行Aop,然后将代理对象放到第二级缓存中,这时候Bservice在注入Aservice属性的时候,就从二级缓存map中能够找到。接着在第五步正常Aop的地方
先去判断有没有提前进行过Aop 如果有进行过Aop 那么就不需要再进行Aop,直接将在第二步生成的代理对象放到单例池中去。这样就能保证放到单例池中的和我们注入属性的对象是同一个对象。

如果是使用了Aop 那么我们是要给属性注入的是代理对象的,而不应该是原始对象


注意:---- 这个时候进行的属性填充是我们的原始对象,代理对象不进行属性填充。

正常情况下 我们就是在第五步进行Aop的



我们都知道Aop是可有可无的并不是一定要进行的,但是如果不进行Aop,那么在去将Aop提前到第二步操作就会有问题了。那问题来了,我怎么去判断什么时候进行AOP,然后再去将Aop提前呢?
也就是我们的重点,什么时候将Aop提前?
当出现了循环依赖,我们才需要提前进行Aop
那么问题又来了,我们怎么去判断出现了循环依赖呢? 
    如果我们一共有12步骤,那么我们在哪一步去判断出现了循环依赖最合适呢?
        其实在第8步去判断是最方便的。
        比如我们在的二步 将创建的bservice放入到一个map中去,然后我们在第8步的时候从单例池中找不到的时候接着去第一步放到map中去找,找到了则表明出现了循环依赖,那么这样就能判断出现了循环依赖。那么一旦判断出现了循环依赖,那么我就将AOP进行提前-Aop--代理对象---	
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring循环依赖指的是在Spring中,多个Bean之间存在相互依赖的情况。具体来说,当一个Bean A依赖于另一个Bean B,同Bean B也依赖于Bean A,就形成了循环依赖。这种情况下,Spring需要解决Bean的创建和依赖注入的顺序问题。 在Spring中,循环依赖问题是由于Bean的生命周期所引起的。SpringBean生命周期包括了Bean的实例化、属性注入、初始化以及销毁等过程。当出现循环依赖Spring通过使用“提前暴露”的方式来解决这个问题。 具体来说,当Spring创建Bean A,发现它依赖于Bean B,于是创建一个A的半成品对象,并将其暂放入一个缓存中。然后,Spring继续创建Bean B,并将其注入到A的属性中。接着,Spring继续完成B的创建,并将其放入缓存中。最后,Spring将A的半成品对象交给B进行依赖注入,完成A的创建,并将其从缓存中移除。 需要注意的是,Spring循环依赖有一定的限制条件。例如,如果Bean A和Bean B都是单例模式,那么它们之间的循环依赖是无法解决的。因为单例模式下,Bean的创建和依赖注入是同进行的,无法通过缓存来解决循环依赖。在这种情况下,程序员需要手动调整Bean的依赖关系或使用其他解决方案来避免循环依赖的问题。 综上所述,Spring循环依赖是指在Spring中多个Bean之间存在相互依赖的情况。Spring通过使用缓存和提前暴露的方式来解决循环依赖问题,但在某些情况下有一定的限制条件需要注意。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值