首页 > 代码库 > spring中的相互引用问题

spring中的相互引用问题

IOC指spring来创建对象实例,而不是Java代码中来做。

DI指spring根据对象的关系来注入相互之间的关系。


DI会引起相互引用的问题,即两个对象相互引用、相互依赖,类似于死锁的问题导致系统无法完成实例化。

报错如下:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name ‘myBoss2‘: Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:347)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
	... 61 more

解决办法是,不适用构造器注入,使用属性注入方式即可。其原理是属性注入方式是,先创建对象再去给对象的属性赋值。

代码如下:

xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 通过属性注入方式的相互引用 -->
    <bean id="myBoss1" class="beans.Boss">
        <property name="age" value="http://www.mamicode.com/10"/>
        <property name="male" value="http://www.mamicode.com/false"/>
        <property name="name" value="http://www.mamicode.com/zhouhui"/>
        <!-- 引用car实例 -->
        <property name="car" ref="myCar1"/>
    </bean>

    <bean id="myCar1" class="beans.Car">
        <property name="brand" value="http://www.mamicode.com/audi"/>
        <property name="price" value="http://www.mamicode.com/10"/>
        <!-- 引用boss对象 -->
        <property name="boss" ref="myBoss1"/>
    </bean>


    <!-- 通过构造器注入方式的相互引用 -->
    <bean id="myBoss2" class="beans.Boss">
        <constructor-arg name="age" value="http://www.mamicode.com/10"/>
        <constructor-arg name="isMale" value="http://www.mamicode.com/true"/>
        <constructor-arg name="name" value="http://www.mamicode.com/zhang"/>
        <!-- 引用car实例 -->
        <constructor-arg name="car" ref="myCar2"/>
    </bean>

    <bean id="myCar2" class="beans.Car">
        <constructor-arg name="brand" value="http://www.mamicode.com/benz"/>
        <constructor-arg name="price" value="http://www.mamicode.com/100"/>
        <!-- 引用boss对象 -->
        <constructor-arg name="boss" ref="myBoss2"/>
    </bean>


</beans>


java代码:

@Test
public void testLoop(){
    System.out.println("===========testLoop======================");
    System.out.println(myCar1);
    System.out.println(myBoss1);
    System.out.println(myBoss2);
    System.out.println(myCar2);
    System.out.println("===========testLoop======================");
}

其中 myCar1 myBoss1是能正常执行的,加上myBoss2 myCar2之后就会报错。


需要特别注意的是,如果bean都是单例的,spring容易会缓存实例,属性注入的相互引用没有问题。不过如果是多例的bean,相互引用及时是属性注入方式,还是会报错。

<!-- 通过属性注入方式的相互引用 -->
<bean id="myBoss3" class="beans.Boss" scope="prototype">
    <property name="age" value="http://www.mamicode.com/10"/>
    <property name="male" value="http://www.mamicode.com/false"/>
    <property name="name" value="http://www.mamicode.com/zhouhui"/>
    <!-- 引用car实例 -->
    <property name="car" ref="myCar3"/>
</bean>

<bean id="myCar3" class="beans.Car" scope="prototype">
    <property name="brand" value="http://www.mamicode.com/audi"/>
    <property name="price" value="http://www.mamicode.com/10"/>
    <!-- 引用boss对象 -->
    <property name="boss" ref="myBoss3"/>
</bean>

scope="prototype" 意思是 每次请求都会创建一个实例对象。两者的区别是:有状态的bean都使用Prototype作用域,无状态的一般都使用singleton单例作用域。

对于“prototype”作用域Bean,Spring容器无法完成依赖注入,因为“prototype”作用域的Bean,Spring容
器不进行缓存,因此无法提前暴露一个创建中的Bean。

spring中的相互引用问题