Spring循环依赖问题(笔记)

  • 时间:
  • 浏览:
  • 来源:互联网

问题来源:

A类中有成员变量B类的对象。

B类中也有成员变量A类的对象。

// 简单来说就,就是如下情况

class A {
    @Autowire
    B b;
}

class B {
    @Autowire
    A a;
}

在一开始的开始

也就是程序第一次获取A的实例时,需要从spring容器单例池中获取。但此时单例池中还没有A的实例,所以要new 一个A对象。

在A实例 创建和初始化的时候,要获取成员变量b的实例,这也需要从单例池中获取,但此时B类在池子中也没有对象,也需要new一个。

在B实例 创建和初始化的时候,要获取成员变量a的实例,这就造成了在创建的时候循环依赖,都需要对方一个已经创建好的实例。

 

 



解决思路

一个单例池肯定是不够的,增加一个半成品池,也就是二级缓存的机制。

在第一步A实例化之后,将A的半成品实例放到这个半成品池子当中,这样子,当B初始化的时候,直接从半成品池子获取A的半成品实例,等B初始化完成之后,再完成A之后初始化操作。

最后将A的实例从半成品 转移到 单例池中,即可解决 循环依赖的问题。

 

 

 

但是,在AOP的时候,仅靠二级缓存是不行的!!

 

在AOP的情景, A的成员变量b,不是B的实例,而是B的动态代理实例 ,可以看做 $b。

而B的成员变量a,也不是A的实例,而是A的动态代理实例,可以看做 $a.

如果继续采用二级缓存的话,半成品池子里面放的只有 实例,而不是 动态代理实例,是行不通的。

需要一个 工厂池,也就是三级缓存的机制,用来获取A的代理对象。

 

在上面步骤中,A实例创建时,在工厂池 中添加一个 半成品的a。

然后在初始化的时候需要一个B的动态代理实例,于是走B的创建初始化流程。

B实例创建时,也会在工厂池中添加一个半成品的b,

然后B初始化的时候,从工厂池中获取半成品a,并调用他的提前引用方法,获取到a的动态代理对象,也就是$a. 

将动态代理实例 $a 放入到 半成品池子里面去。再用半成品池里面 $a 去填充B实例里面的成员变量a。

完成后续B的初始化操作之后,调用b对象的后置处理,创建动态代理实例 $b,并将$b 放入到 单例池里面去,B的实例化操作便完成了。

B完成之后,又回到A的初始化后续步骤,直接将$b 从单例池中赋值给A的成员变量即可。

当然,同样会调用A的后置处理,但因为前面通过提前引用的方式,已经创建了A的动态代理实例$a,所以后置处理并不会再去创建 A的动态代理实例,此时直接将$a 从半成品池中迁移到单例池即可。

 

 

Spring 解决循环依赖的思路基本就这样了,三级缓存机制。

本文链接http://www.dzjqx.cn/news/show-617248.html