前言



  1. JDK11 (JDK8的新特性还没写,就用上11了)
  2. spring 5.2.X (应该是此类文章的最新版本了)
  3. Gradle 6.5.1 (gradle要是玩不好的话构建这个源码要花一番功夫 )

一、Spring解决循环依赖的前置条件

  1. 出现循环依赖的Bean必须要是单例对象(singleton),如果依赖prototype原型对象就不会有这个需求,需要就new就完事儿。
  2. 依赖注入的方式不能全是构造器注入的方式(只能解决setter方法的循环依赖,这个说法不对。)

关于第二点的说明:
最重要的一点就是,AB循环依赖,在spring默认按照beanName的英文字母顺序实例化的时候,A注入B用的有参构造,B注入A用是setter方法时无法注入成功,但是反过来却可以。

spring新版本 不支持循环依赖 spring支持循环依赖吗_spring

spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_02

二、学习是生命长河中泛起的波光粼粼

1.凭印象说说

spring新版本 不支持循环依赖 spring支持循环依赖吗_java_03

  • 正常实例化一个对象,先编译成class,类加载器加载到jvm的堆(分配内存)中,再把引用指针指向栈的引用对象。(这方面看的不多暂时这么理解)
  • spring实例化对象,有一套很规范很长的流程(毕竟要考虑到咱开发者的所有需求的前提下管理众多的bean对象)。
  1. spring会解析需要实例化的对象(OOO表示),把它的元数据(别人介绍你的时候不会指着你说这就是你,还会附带的介绍你是不是富二代,有几个前女友,是不是程序员,这样的就属于元数据,spring官方用beanDefintion对象表示)解析出来。
  2. 在实例化之前的一些验证过后开始实例化
  3. 验证处理完毕后开始实例化对象,先标记下此对象处于正在创建的过程中,createBean的时候会遇到spring的后置处理BeanPostProcessors处理(spring实例化一个对象一共会经过九个后置处理对象的依次处理)
  4. 创建对象后,紧接着在第四次后置处理器中addSingletonFactory(了解过spring三级缓存的同学应该知道,这里就是向第二级缓存中添加此对象的单例工厂。singletonObjects:一级缓存指的是所有创建好了的单例Bean,单例池也是小白理解的spring容器),紧接着就是再remove掉这个beanName对应的earlySingletonObjects(也就是三级缓存,存放的是未注入属性的Bean)中的对象(看了下代码就一个地方有put对应的有两个地方remove,暂且理解为确保此对象只有一个bean工厂吧)。
  5. 到这一步是属性注入了,在populateBean自动注入方法中会执行第五次第六次后置处理器BeanPostProcessors,此处是循环引用的重点了。因为属性注入发现引用了另一个未实例化的对象。那就开始属性注入吧,here we go。
  6. 属性注入的时候,spring把所有的后置处理拿出来挨个判断,挨个处理,结果有个叫做AutowiredAnnotationBeanPostProcessor的后置处理器表示也要来尝试下,结果发现你用了@Autowired注解注入了一个没有实例化的XXX对象。那么这个后置处理器开始表演了。(面试官问@Autowired和@Resoure注入属性的区别时除了可以说依据类型和名字注入的区别外还可以说一个是spring后置处理器处理一个是jdk的annotation下的注解,很牛掰有没有)。在后置处理器AutowiredAnnotationBeanPostProcessor的metadata.inject方法中开始属性注入。
  7. inject方法会循环遍历所有此类型需要注入的对象,经过一系列的验证之后发现这个XXX对象现在就要注入,那没办法只能给他注入。这里会判断是不是AutowireCapableBeanFactory类型的BeanFactory,是就用这种类型处理不是就自个儿类型处理(不太重要)。
  8. 接下来进入getSingleton()方法里进入三个缓存斗地主环节(谁有牌谁出,都没有的话轮到singletonFactories出牌),此处会返回最开始要实例化对象OOO的代理对象给到XXX对象完成属性注入,然后再返回XXX对象给OOO完成属性注入。到此整个循环引用走完了。(有不准确的地方欢迎指正,感谢。)

2.源码流程

  1. 先看下笔者的自定义类(三个初始化实例和一个启动类)

spring新版本 不支持循环依赖 spring支持循环依赖吗_java_04


spring新版本 不支持循环依赖 spring支持循环依赖吗_实例化_05


spring新版本 不支持循环依赖 spring支持循环依赖吗_spring_06


spring新版本 不支持循环依赖 spring支持循环依赖吗_spring_07

  1. 当然从refresh()开始 spring体系过于庞大,此处只研究循环依赖,其它的断点直接过了.
  2. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring_08

  3. 毫无疑问实例化自定义对象从这个对象开finishBeanFactoryInitialization() 部分spring自带的对象(后置处理器等)在此之前已经实例化,在单例池已经存在。
  4. spring新版本 不支持循环依赖 spring支持循环依赖吗_后端_09


  5. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_10

  6. 可以看到前期准备的需要实例化的beanNames一共有7个,后三个是咱的 循环依赖是最后两个
  7. spring新版本 不支持循环依赖 spring支持循环依赖吗_实例化_11

  8. 它首先会去单例池这边看下 发现前四个beanName都有了直接get出来美滋滋,这四个也不是咱的关注对象 直接过了。
  9. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_12

  10. 这里是咱的重头戏 开始实例化indexService对象,先判断是不是抽象类单例和懒加载已经bean工厂类型,很显然都不是所以直接进入开始实例化普通的bean, getBean(beanName) 方法

spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_13

  1. 然后走到这里在单例池中找 ,很明显现在啥也没有,也没有被标记为正在创建中,直接返回null
  2. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_14


  3. spring新版本 不支持循环依赖 spring支持循环依赖吗_java_15

  4. beanNames里前四个是可以直接从单例池中获取到,所以进入这个getObjectForBeanInstance()方法,咱是null所以打扰了
  5. spring新版本 不支持循环依赖 spring支持循环依赖吗_后端_16

  6. 接着是个小插曲,会判断是不是在创建过程中很显然是在创建但是没有标记,然后查找对应的BeanFactory也没有,然后在标记此对象正在创建。private final Set alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));放进这个Set里就叫在标记了
  7. spring新版本 不支持循环依赖 spring支持循环依赖吗_java_17

  8. 接下来getMergedLocalBeanDefinition(beanName)合并bean获取到beanName对应的BeanDefinition,可以看到经过这个操作已经获取到了这个beanName对应的beanClass对象里面包含类加载器和相应的构造方法,为后面spring反射实例化此对象做准备,接下来会看下有没有dependsOn注解,我们没有,过了
  9. spring新版本 不支持循环依赖 spring支持循环依赖吗_实例化_18

  10. getSingleton()中会检查是否在单例池中然后放入此Set集合 表示正在创建private final Set singletonsCurrentlyInCreation =
    Collections.newSetFromMap(new ConcurrentHashMap<>(16));
    这里添加的的singletonsCurrentlyInCreation就是步骤7里判断的那个集合。也就是说下次的场景中再去getSingleton(“indexService”)的时候,是可以通过第一个if的;
  11. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_19

  12. 可以看到经过上图中的createBean()里的resolveBeanClass方法后从beanDefintion中获取了IndexService的class。
    但是这个class经过spring的第一个后置处理器的处理过后没有得到一个对象(没看这里面是啥情况),接下来spring会通过接下来的后置处理器通过反射来得到需要的IndexService的JavaBeans包装类BeanWrapper

spring新版本 不支持循环依赖 spring支持循环依赖吗_后端_20

  1. 此处第一次调用spring的后置处理器 ,九个处理器内容过多以后有时间再写吧。

spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_21

  1. 可以看到没有找到这里合适的构造函数。
  2. spring新版本 不支持循环依赖 spring支持循环依赖吗_实例化_22

  3. 使用默认的构造函数实例化bean
  4. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring_23

  5. 最后会来的这个方法里用instantiateClass下的ctor.newInstance(argsWithDefaultValues)通过反射获得对象BeanWrapper
  6. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring_24

  7. 可以看到此处获取了Object bean 是IndexService@2247
    此处仅仅是实例化出来了这个bean, 没有属性注入,aop,调用初始化方法
    , @PostConstruct生命周期的初始化回调方法, 都没做。

spring新版本 不支持循环依赖 spring支持循环依赖吗_后端_25

  1. 接下来会添加这个对象的单例工厂到二级缓存中addSingletonFactory
  2. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring_26

  3. 在populateBean() 中填充属性,也就是自动注入,里面会完成第五次第六次后置处理器的调用,但是之前的代码显示UserService还未实例化且注入了IndexService中,所以此处的属性注入就引出了循环依赖的问题,继续往里面看。

spring新版本 不支持循环依赖 spring支持循环依赖吗_java_27

  1. 可以看到在populateBean()方法中 会把spring所有的后置处理器拿出来遍历,处理的操作例如aop,PostConstruct初始化方法,属性填充, @Autowaire注解对应的处理器都在此处开始干活。
  2. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_28

  3. 当轮询到AutowiredAnnotationBeanPostProcessor后置处理器的时候,会处理我们用@Autowired注解注入的 Userservice userservice 对象 但是这个对象还没有被实例化,所以在这个后置处理器中会实例化这个对象
  4. spring新版本 不支持循环依赖 spring支持循环依赖吗_后端_29


  5. spring新版本 不支持循环依赖 spring支持循环依赖吗_后端_30

  6. 可以看到需要注入的目标对象target中Userservice=null
  7. spring新版本 不支持循环依赖 spring支持循环依赖吗_实例化_31

  8. AutowiredAnnotationBeanPostProcessor后置处理器在获取Userservice的RootBeanDefinition后在
    isAutowireCandidate的resolveBeanClass方法中获取Userservice的class,获取了一顿操作发现什么都没有因为这个对象压根还没创建,最后又去单例池里找没找到。

spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_32

spring新版本 不支持循环依赖 spring支持循环依赖吗_spring_33

  1. 尝试去单例池中获取 发现没有这个实例 ,这就跟我们当初找IndexService一样样的,找不到就给他实例化,流程和上面IndexService一样样的重复的就不看了(下面主要是看下省略截图的调用栈。)
  2. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring_34

  3. 这里到了重要环节 换作给Userservic进行属性注入了

spring新版本 不支持循环依赖 spring支持循环依赖吗_后端_35

  1. 可以看到要注入的目标对象desc是IndexService,被注入的对象beanName是userService。
  2. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_36

  3. 可以看到AutowiredAnnotationBeanPostProcessor后置处理器此处再此去单例池中找IndexService了 上次是去找IndexService中的UserviceService,发现没有并且不在创建过程中然后返回了null但是这次不一样了 ,IndexService在上面创建的过程中已经标记为正在创建过程中,且创建了对应的beanFactory。
  4. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_37


  5. spring新版本 不支持循环依赖 spring支持循环依赖吗_java_38

看到上图 beanFactory.getBean(beanName),一定就很熟悉了有木有。

  1. 可以看到,IndexService的singletonObject虽然为null 但在isSingletonCurrentlyInCreation是否是在创建过程中判断通过.
  2. spring新版本 不支持循环依赖 spring支持循环依赖吗_spring新版本 不支持循环依赖_39


  3. spring新版本 不支持循环依赖 spring支持循环依赖吗_实例化_40

  4. 然后在单例池singletonObjects和三级缓存earlySingletonObjects(半成品)中均未获得这个对象,最后去二级缓存singletonFactories中获取 ,很显然有对应的bean工厂可以获取到,用IndexService的singletonFactory获取到它的代理对象放进三级缓存,然后删除IndexService的singletonFactory。

spring新版本 不支持循环依赖 spring支持循环依赖吗_实例化_41

  1. 接下来就是逐层返回对象,把IndexService注入到UserService,再把UserService注入到IndexService,整个循环依赖解决

总结

所有的成果都是为了提高体验,技术也不例外,相信技术与艺术的长河不久会汇聚到一起,而不是受困于当下。额外感谢路神的技术博客,好好学习,天天向上。