spring中的相互引用問題
阿新 • • 發佈:2017-08-11
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中的相互引用問題