循环依赖是多个类之间循环的嵌套引用,如果我们使用 new object 的方式发生循环依赖那么程序会一直循环调用,直到内存溢出。那么Spring 是怎么处理循环依赖的呢?
先看看Spring Bean实例化过程
方式一 带参数的构造函数
Spring容器会将每一个正在创建的 Bean 标识符放在一个 “当前创建Bean池” 中,Bean标识符在创建过程中会一直存在于这个池中。
因此如果在创建Bean过程中发现自己已经在 “当前创建Bean池” 的时候就会抛出 BeanCurrentlyInCreationException 表示循环依赖。成功创建完的 Bean 会从 “当前创建Bean池” 中清除掉。
方式二 单例中的setter方法
Spring Bean 在实例化过程中是先将Bean对象实例化之后再设置对象属性,所以实例化不受影响。
Spring会将这个实例化完成的对象放到一个Map中,并且Spring提供了获取这个未设置属性的实例化对象引用的方法。
所以当Spring实例化了ObjectA、ObjectB、ObjectC后,紧接着会去设置对象的属性,此时ObjectA依赖ObjectB,就会去Map中取出存在里面的单例ObjectB对象,同理ObjectB取ObjectC,ObjectC取ObjectA,那么不会出现问题。
方式三 多例中的setter方式
多例模式 scope=“prototype” 意味着每次请求都会创建一个实例对象。
两者的区别是:有状态的bean都使用Prototype作用域,无状态的一般都使用singleton单例作用域。
对于“prototype”作用域Bean,Spring容器无法完成依赖注入,因为“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。