1.概念回顾
1. 概念
1. 在本系列,《3.IOC容器》这章中,提到过循环依赖的概念: A 依赖 B, B 也依赖 A:
public Class A {
private B b;
public A(B b) {
this.b= b;
}
// setter and getter
}
public Class B {
private A a;
public B(A a) {
this.a = a;
}
// setter and getter
}
运行时,抛出BeanCurrentlyInCreationException.
2. scope为prototype
- 不能使用循环依赖,原因:
// A 依赖 B, B依赖 A: A 创建中,发现需要 B, 去创建 B, B创建中,发现需要 A
// 去创建 A, 由于 scope是 prototype, 会建立一个新的 A, 会发生 stackoverflow?
// 是的,会stackoverflow.
// Method threw 'java.lang.StackOverflowError' exception. Cannot evaluate java.lang.StackOverflowError.toString()
3. scope为 singleton
1. 构造器
无法解决循环依赖: A 构造时,需要 B 的实例, B需要先实例化,B通过构造器实例化,发现需要 A的实例,这显然,陷入了死循环
2. Setter
可以解决循环依赖(但是由于过早曝光,创建出来的实例无任何属性填充、后续处理等,是个”生肉“): 可以先通过 A/B 无参构造构造器把 A/B实例先创建出来,再通过setter扶植给依赖。
2.解决之道
通过Setter方法解决,大致过程如下:
通过提前暴露一个单例工厂方法,从而,其他的bean能够引用到该bean, 如下代码所示:
addSingletonFactory(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
})
具体步骤如下:
1) Spring容器创建单例 A a bean, 首先根据无参构造器创建bean, 并暴露一个ObjectFactory 用于返回一个提前暴露一个创建的bean, 并将 a 标识符放入当前创建bean的池里,然后进行setter,注入 B b.
2) Spring创建 单例 B b, 首先根据无参构造器创建 bean 实例 b. 并通过 objectFactory进行暴露对 b的引用。再执行 setter, 这时,需要注入a. 由于1)中 提前暴露了对 a的应用 objectFactory, 可以通过 objectFactory 拿到 a.注入 a. 之后返回 b.
3) 最后,a 通过objectFactory 拿到 b, 注入。完成。