Spring循环依赖

来源:互联网 发布:mac guid分区方案 编辑:程序博客网 时间:2024/06/07 15:52

Spring循环依赖指的是类A依赖B,B又依赖A。这就依赖注入的时候会带来一定问题。下面说明一下,循环依赖的情况。

存在构造注入

public class AServieImpl implements AService{    private TestService testService;    public void setTestService(TestService testService){        this.testService=testService;    }    public AServieImpl(){    }}
public class TestServiceImpl implements TestService {    private AService aService;    @Override    public void test() {        // TODO 自动生成的方法存根        System.out.println("test serviceimpl");    }    public TestServiceImpl(AService aService){        this.aService=aService;    }}
 <bean class="com.test.service.impl.AServiceImpl" name="aService" id="aService" >        <property name="testService" ref="testService"></property>     </bean>              <bean class="com.test.service.impl.TestServiceImpl" name="testService" id="testService" >        <constructor-arg name="aService" ref="aService"></constructor-arg>     </bean>

报错:
org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [com.test.service.impl.AServiceImpl] for bean with name ‘aService’ defined in ServletContext resource [/WEB-INF/spring.xml];

构造注入是先初始化依赖对象,在实例化本身的。所以,当TestServiceImpl要实例化时,先初始化AService,然后去找AService。然而设值注入是先实例本身,在初始化依赖对象的。所以AService先实例化本身,同时要求依赖TestServiceImpl,然后并没有找到TestServiceImpl。所以报错。

Spring容器将每一个正在创建的bean标识符放在一个”当前创建bean池”中,bean标识符在创建过程中将一直保持在这个池中,因此如果在创建bean过程中发现自己已经在”当前创建bean池”里时,将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的bean将从”当前创建bean池”中清除掉。对于setter注入造成的依赖是通过Spring容器提前暴露刚完成无参构造函数实例化但未完成其他步骤(如setter注入)的bean来完成的,而且只能解决单例作用域的bean循环依赖。通过提前暴露一个单例工厂方法,从而使其他bean能引用到该bean:

addSingletonFactory(beanName, new ObjectFactory() {         public Object getObject() throws BeansException {             return getEarlyBeanReference(beanName, mbd, bean);         }     }); 

单体的设值注入

public class AServieImpl implements AService{    private TestService testService;    public void setTestService(TestService testService){        this.testService=testService;    }}
public class TestServiceImpl implements TestService {    private AService aService;    @Override    public void test() {        // TODO 自动生成的方法存根        System.out.println("test serviceimpl");    }    public void setaService(AService aService) {        this.aService = aService;    }}
<bean class="com.test.service.impl.AServieImpl" name="aService" id="aService" >        <property name="testService" ref="testService"></property>     </bean>              <bean class="com.test.service.impl.TestServiceImpl" name="testService" id="testService" >        <property name="aService" ref="aService"></property>     </bean>

单体的set注入是可以的。
但对于非单体就不行了。因为Spring容器不进行缓存”prototype”作用域的bean,因此无法提前暴露一个创建中的bean。