Spring 循环引用 ——理解singleton与prototype初始化的区别

本文详细探讨了Spring框架中singleton和prototype两种作用域下的循环引用问题。针对构造器、设值注入及混合模式的循环依赖,分析了Spring如何处理以及为何在某些情况下无法完成注入。此外,还深入剖析了singleton对象的初始化过程,包括关键属性、创建流程及源码分析,解释了为什么不能采用构造注入。最后,讨论了prototype的初始化流程,揭示了其不能实现循环引用的原因。
摘要由CSDN通过智能技术生成

所谓的循环引用,就是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空了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值