所谓的循环引用,就是A依赖B,B又依赖A,A与B两个对象相互持有。像下面这种情况:
class A
{
B b;
public A(B b) {
this.b=b;
}
}
class B
{
A a;
public B(A a )
{
this.a=a;
}
}
我们知道spring在获取对象或者在加载的时候,触发依赖注入。例如触发A对象的依赖注入,发现需要B对象,而此时B还没有初始化,就去实例化B对象,而又需要A对象,这样就进入了一种死循环状态,有点像操作系统里面的死锁。似乎这种情况发生了,Spring就陷入僵局了。显然Spring有方法去解决这个问题。对于依赖注入的情况,大致分为构造注入和设值注入两种方式,而实际上因为Spring注入的触发机制不一样,这个问题又被分为singleton对象和prototype(其他三个作用域大致相同)对象的区别。我们可以把问题大致分为三类。
1 singleton对象循环引用
1.1 构造器循环依赖
这种依赖Spring是无法给你解决的,将会抛出BeanCurrentlyInCreationException异常。来看一下测试代码
(1) 定义两个类 A,B 构成构造成循环依赖的情况
class A
{
B b;
public A(B b) {
this.b=b;
}
}
class B
{
A a;
public B(A a )
{
this.a=a;
}
}
(2) 配置文件中配置两个类,在不指明作用域的时候,默认为singleton对象
<bean id="xiaoA" class="com.songxu.learn.A">
<constructor-arg name="b" ref="xiaoB" />
</bean>
<bean id="xiaoB" class="com.songxu.learn.B">
<constructor-arg name="a" ref="xiaoA" />
</bean>
(3)加载配置文件,两个类默认被加载以及注入
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
<span style="font-size:18px;"> </span>
(4) 结果抛出了异常,来看一下日志输出
2015-08-01 02:39:15,869>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2ef5e5e3: defining beans [xiaoA,xiaoB]; root of factory hierarchy
2015-08-01 02:39:15,869>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoA'
2015-08-01 02:39:15,869>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoA'
2015-08-01 02:39:15,889>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoB'
2015-08-01 02:39:15,889>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoB'
2015-08-01 02:39:15,889>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoA'
2015-08-01 02:39:15,889>>>>[org.springframework.context.support.AbstractApplicationContext]-[WARN] >>>>Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xiaoA' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'xiaoB' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xiaoB' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'xiaoA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'xiaoA': Requested bean is currently in creation: Is there an unresolvable circular reference?
这个过程是这样的,容器构造Class A的对象,发现构造参数需要一个ClassB的对象,而此时容器中没有ClassB的实例,因此转到ClassB的实例化过程,ClassB构造又需要ClassA,这样进入了循环状态。双方都无法完成构造的过程,因此抛出了异常。
1.2 设值注入循环依赖
对于设值注入的情况,循环依赖是可以完成的。来看一下测试代码。
(1) 构造两个类 A,B 构成循环依赖,并且使用设值注入的方式。
class CircleA
{
private CircleB b;
public CircleA(CircleB b)
{
this.b=b;
}
public CircleB getB() {
return b;
}
public void setB(CircleB b) {
this.b = b;
}
public CircleA()
{
}
}
class CircleB
{
private CircleA a;
public CircleA getA() {
return a;
}
public void setA(CircleA a) {
this.a = a;
}
public CircleB(CircleA a)
{
this.a=a;
}
public CircleB()
{
}
}
(2) 配置文件 采用默认的方式
<bean id="circleA" class="com.songxu.learn.CircleA" >
<property name="b" ref="circleB"></property>
</bean>
<bean id="circleB" class="com.songxu.learn.CircleB" >
<property name="a" ref="circleA"></property>
</bean>
(3)加载配置文件,两个类默认被加载以及注入
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
(4)结果运行通过,看一下日志输出
2015-08-01 03:41:32,302>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@100fc185: defining beans [circleA,circleB]; root of factory hierarchy
2015-08-01 03:41:32,302>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleA'
2015-08-01 03:41:32,302>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleA'
2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleA' to allow for resolving potential circular references
2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleB'
2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleB'
2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleB' to allow for resolving potential circular references
2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning eagerly cached instance of singleton bean 'circleA' that is not fully initialized yet - a consequence of a circular reference
2015-08-01 03:41:32,322>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleB'
2015-08-01 03:41:32,322>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleA'
2015-08-01 03:41:32,322>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning cached instance of singleton bean 'circleB'
这个过程是这样的,
A构造空对象放入缓存池中(暂且称为A空),触发了B对象注入,然后去构造B对象,又触发了对A对象的注入,这个时候缓存中已经有一个空的A对象,就把A空对象注入给B,
然后B构造完成,返回给A,这时A对象已经完成了注入。而同时B中持有的A对象也不再是A空了