1. 程式人生 > >spring中的相互引用問題

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="10"/>
        <property name="male" value="false"/>
        <property name="name" value="zhouhui"/>
        <!-- 引用car實例 -->
        <property name="car" ref="myCar1"/>
    </bean>

    <bean id="myCar1" class="beans.Car">
        <property name="brand" value="audi"/>
        <property name="price" value="10"/>
        <!-- 引用boss對象 -->
        <property name="boss" ref="myBoss1"/>
    </bean>


    <!-- 通過構造器註入方式的相互引用 -->
    <bean id="myBoss2" class="beans.Boss">
        <constructor-arg name="age" value="10"/>
        <constructor-arg name="isMale" value="true"/>
        <constructor-arg name="name" value="zhang"/>
        <!-- 引用car實例 -->
        <constructor-arg name="car" ref="myCar2"/>
    </bean>

    <bean id="myCar2" class="beans.Car">
        <constructor-arg name="brand" value="benz"/>
        <constructor-arg name="price" value="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="10"/>
    <property name="male" value="false"/>
    <property name="name" value="zhouhui"/>
    <!-- 引用car實例 -->
    <property name="car" ref="myCar3"/>
</bean>

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

scope="prototype" 意思是 每次請求都會創建一個實例對象。兩者的區別是:有狀態的bean都使用Prototype作用域,無狀態的一般都使用singleton單例作用域。

對於“prototype”作用域Bean,Spring容器無法完成依賴註入,因為“prototype”作用域的Bean,Spring容
器不進行緩存,因此無法提前暴露一個創建中的Bean。

spring中的相互引用問題