Spring(循环依赖,有问题欢迎讨论,小白在学习)

循环依赖:

        类与类之间的关系形成闭环。

                                                        

        注意:这不是函数的循环调用,是对象的相互依赖关系。循环调用就是一个死循环,除非又终结条件

Spring中依赖场景有:

        构造器注入的循环依赖;如果两个bean在构造器参数中相互依赖,Spring无法解决这种循环依赖。因为创建bean是需要先解析构造器,解析不了循环依赖

        单例bean的循环依赖:当两个单例bean相互依赖时,如果无法通过代理来解决循环依赖,Spring将无法完成bean的初始化;

        原型bean的循环依赖:原型bean时每次请求时都会创建一个新实例,循环依赖会导致无限递归创建bean实例

1、构造器的循环依赖

        一个概念Spring先创建单例A,A依赖B,然后A已经放入“bean池”,此时创建B,B依赖C,将B放在当前的“bean池”,创建C,C依赖A,此时A在池中所以会报错,因为bean并没有初始化完,所以A没有释放,所以会报依赖错误。(初始化完的Bean会从池中删除)

2、setter方式单例

        Spring是先将Bean对象实例化【依赖无参构造参数】-----》在设置对象属性

 

        Spring先是构造实例化bean对象,此时spring会将这个实例化结束的对象放到一个map里面,此时Spring提供获取这个未设置属性的实例化对象引用方法。

3、setter方式原型,prototype

        scope="prototype" 意思是 每次请求都会创建一个实例对象。两者的区别是:有状态的bean都使用Prototype作用域,无状态的一般都使用singleton单例作用域。对于“prototype”作用域Bean,Spring容器无法完成依赖注入,因为“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。

三级缓存

第一级缓存作用?Map<String, Object> singletonObjects

        用于存储单例模式下创建的bean实例(已经创建完的)

        该缓存是对外使用的,指的是使用Spring框架的程序员

        存储什么数据?

                K:bean的名称

                V:bean的实例对象(有代理对象则指的是代理对象,已经创建完毕)

第二级缓存作用?Map<String, Object> earlySingletonObjects

        这个缓存用于存储早期暴露的 Singleton Bean 实例。在解决循环依赖时,正在创建的 Bean 实例会被提前暴露并放入这个缓存中。

        该缓存是对内使用的,指的就是Spring框架内部逻辑使用该缓存。

        存储什么数据?

                K:bean的名称

                V:bean的实例对象(有代理对象则指的是代理对象,该Bean还在创建中)

第三级缓存:Map<String, ObjectFactory<?>> singletonFactories

        这个缓存用于存储正在创建中的 Singleton Bean 的 ObjectFactory。当正在创建的 Bean 实例还未完全初始化时,其 ObjectFactory 会被放入这个缓存中。

        该缓存是对内使用的,指的就是Spring框架内部逻辑使用该缓存。

        此缓存是解决循环依赖最大的功臣

        存储什么数据?

        K:bean的名称

        V:ObjectFactory,该对象持有提前暴露的bean的引用

        为什么要创建ObjectFactory

                ObjectFactory是为了处理循环依赖中的提前长生代理对象的问题。在循环依赖过程中,当两个及以上的bean相互依赖时,没办法直接完成初始化。这个时候Spring提出来三级缓存,采用第三级缓存给正在创建中的bean提供一个ObjectFactory的实例。通过ObjectFactory能够提前暴露一个尚未完全初始化的Bean的实例工厂对象,而不是直接暴露bean的本身,这样其他Bean使用该bean时,ObjectFactory提供的代理对象来替代真正的bean实例,解决循环问题

解决

不要使用基于构造函数的依赖注入,可以通过以下方式解决:

  1.在字段上使用@Autowired注解,让Spring决定在合适的时机注入

  2.用基于setter方法的依赖注入。

总结(补充)

        1、搞清楚Spring三级缓存的作用?

                三级缓存主要分为单例缓存,早期单例对象缓存,三级缓存。主要优化Bean的创建过程,解决循环依赖和提高性能

                (1)单例缓存:Spring容器启动时,Spring会将所有的单例Bean放入单例缓存中,当获取Bean时,如果单例缓存中存在直接返回,避免重复创建。

                (2)早期单例对象缓存:在单例bean创建的过程中,如果bean类中有依赖其他bean的,spring会将正在创建的bean提前暴露到早期单例对象缓存中,,以便解决循环

                (3)三级缓存:创建单例时,Spring使用三级缓存来缓存BeanDefinition、singleton实例对象和早期的singleton实例对象。三级缓存的作用在于bean的创建过程中进行缓存和提前曝光,以及采用ObjectFactory产生的代理对象进行替换真正的bean实例,解决循环引用问题

        2、搞清楚第三级缓存中ObjectFactory的作用?

                存在循环依赖时,暴露bean的工厂对象而不是本身,用代理对象替换真正的bean

        3、搞清楚为什么需要第二级缓存?

                提前暴露Bean实例;解决循环依赖问题,确保Bean的完整性,

        4、搞清楚什么时候使用三级缓存(添加和查询操作)?

                当容器需要获取某个bean的实例时(查询操作),解决循环依赖。在查询数据时,容器会先检查一级缓存里面的单例缓存中是否存在bean实例,没有去二级缓存中找,有就能不能提前暴露出来,没有去三级缓存里面找,是不是又对应的ObjectFactory创建的代理对象

        5、搞清楚什么时候使用二级缓存(添加和查询操作)?

                在执行添加操作时,Spring容器初始化bean实例时,会将正在创建的bean实例提前暴露到耳机缓存中,让其他bean提前获得正在创建的bean实例

        6、当目标对象产生代理对象时,Spring容器中(第一级缓存)到底存储的是谁?

                代理对象

       注意一点:查询操作时先查一级缓存,在查二级缓存,最后查三级缓存,但是新增的时候,正在创建的bean,所以是二级缓存

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值