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类就是要扫描业务类




原文地址:https://www.cnblogs.com/hkdpp/p/11872372.html