循环依赖问题

一个bean的创建分为如下步骤:

Spring循环依赖问题的解决_Spring

当创建一个简单对象的时候,过程如下:

  • 先从单例池中获取bean,发现无  a
  • 创建  a  的实例
  • 为  a  赋值
  • 把  a  放到单例池中

Spring循环依赖问题的解决_Spring_02

当创建一个对象并且其中有另外一个对象是就变成了这样:

Spring循环依赖问题的解决_Spring_03

但是当在B对象中由引用了A对象,就会变成这样:

Spring循环依赖问题的解决_Spring_04

因为A和B两者相互引用,但是单例池中始终无法创建任一对象,所以会出现死循环。

因此,我们需要添加一个半成品池,先把A初始化出来,放到一个半成品池中。

过程如下:

  • 先从单例池中找A对象,没有则开始创建A对象
  • 实例化A对象,并放入半成品池中
  • 为A对象赋值
  • 赋值时发现引用了B对象  --> 实例化B对象,并放入半成品池中
  • 为B对象赋值
  • 赋值时发现引用了A对象,从单例池中和半成品池中找A对象,并将其赋值
  • 实例化B对象,并放入单例池中
  • 实例化A对象,从半成品池中移除A对象,并放入单例池中

Spring循环依赖问题的解决_Spring_05

这样就解决了死循环创建但是当使用了动态代理后,情况又会有所变化.

先来看一下AOP的执行过程,如图:

Spring循环依赖问题的解决_Spring_06

在bean的创建过程中,创建动态代理的时机是在初始化之后的,如图:

Spring循环依赖问题的解决_Spring_07

这个时候半成品池里放的是没有代理过的A对象,当B去半成品池中获取A对象,获取的是动态代理前的A对象,而我们应该获取的是动态代理后的A对象,这就会出现问题.

Spring循环依赖问题的解决_Spring_08

为了解决AOP的问题,spring又加入了一个工厂池

Spring循环依赖问题的解决_Spring_09

执行过程如下:

  • 当创建A对象的时候会在工厂池中创建factory(a)
  • ....
  • 当给B赋值时,发现引用了A,就会去工厂池中执行getEarlyReference  提前处理方法,生成一个动态代理后的A对象,并放入半成品池中,再赋值给B
  • ...

注意:

当实例化对象A的时候,A对象会产生与之对应的factory(a)方法,只有当某个对象引用A对象时,factory(a)方法才会被执行,从而去通过提前引用的方式创建动态代理对象放入半成品池中

如果说A对象没有被提前引用,factory(a)方法不会执行