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。
时间: 2024-11-08 17:55:19