zoukankan      html  css  js  c++  java
  • spring循环引用-笔记

    创建两个类

    package com.hkdpp.springdemo.service;
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class Test1 {
    
       @Autowired 
    Test2 test2 ;
    }
    package com.hkdpp.springdemo.service;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    
    @Component
    public class Test2  {
    
    
        @Autowired
        Test1 test1 ;
    
    
    }

    步骤:

    默认没有延迟加载,容器启动时创建bean

    注意:容器里放的永远都是bean,不是对象,对象可以理解为是bean的一个半成品。只有spring创建bean的过程结束了,容器里存放的才有这个bean。

    1、spring容器启动时初始化bean,启动时最重要的方法refresh()。首先,在obtainFreshBeanFactory();中创建所有对象的BeanDefinition,在创建bean之前,

    先去单例池(spring容器)获取,第一次发现返回null,然后开始先创建对象的实例(并不是springbean),但是在创建之前有一步操作,就是要把test1实例放入到一个set集合中(在获取不到bean的时候有一个判断条件就是此对象是不是正在创建)继续往下走,有个判断

    一个是看是否支持循环依赖(默认是支持),如果支持,就会把test1实例封装成一个Object放入到二级缓存中(单例工厂)

    ,然后经过一系列的后置处理器,对实例进行一些改造。

    2、其中有一个方法是填充属性值用的,也就是要依赖注入,test1类里有test2属性。要得到test2的bean,还是要先去容器里看有没有,此时没有。

    3、开始创建test2的bean,一样的流程,还是先创建对象实例(并不是springbean),在创建之前有一步操作,就是要把test2实例放入到一个set集合中,

    看是否支持循环依赖(默认是支持),如果支持,就会把test2实例封装成一个Object放入到二级缓存中(单例工厂)

    中间又走到填充属性的方法,此时test2类里发现有test1。

    4、然后去容器里获取test1的bean,也是返回null(容器里获取的是bean,不是对象)

    但是此时的二级缓存和set集合里已经有了test1和test2两个实例对象。表示正在创建过程中。

    5、返回null之后,有个判断表示是否正在创建此对象,也就是set集合里有没有这个对象

    此时是有的。因为上面已经放入了。

     singletonObjects就是容器池(一级缓存,里面放的都是bean)

     isSingletonCurrentlyInCreation 表示是否正在创建,也就是set集合里是否包含此对象

     earlySingletonObjects表示三级缓存

     allowEarlyReference表示是否支持循环引用

     singletonFactories就是二级缓存,也就是单例工厂。

    这里面的3个缓存的作用:

    一级缓存:专门存放springbean

    二级缓存:实际上是单例工厂,为什么不是一个简单的map,而要用一个工厂。是因为spring要对对象还可能要进行改造,很经典的场景就是aop的应用。

    如果只是放入map,就不能进行扩展了,只能是原封不动的返回。工厂模式的应用,工厂就是生产对象用的,但是在产生一个对象之前还可以做很多事。

    三级缓存:其实这个缓存如果去掉,完全可以。它出现的目的是为了解决性能的问题(防止重复生产对象)。

    比如:还有一个test3也引用了test1,根据上面的流程,还要从单例工厂里获取(二级缓存),因为是单例,每次产生的对象都一样,之前已经生产过了,而且放入了三级缓存。

    所以直接去三级缓存去取就行了,不用再工厂里再产生一个了。

    当然,循环引用也可以关闭

    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
            ac.setAllowCircularReferences(true);
            ac.register(AppConfig.class);
            ac.refresh();

    AppConfig类就是要扫描业务类




  • 相关阅读:
    为什么我会认为SAP是世界上最好用最牛逼的ERP系统,没有之一?
    被公司的垃圾XG人事系统吓尿了
    【域控管理】父域的搭建
    【域控管理】域控的必要性
    对.net 程序进行源码混淆
    公司消费一卡通“变法”记
    Oracle研究专题:Oracle系统安装与配置
    数据仓库003
    数据仓库002
    数据仓库001
  • 原文地址:https://www.cnblogs.com/hkdpp/p/11872372.html
Copyright © 2011-2022 走看看