spring循环依赖分析

1:写在前面

这里的循环依赖指的是基于引用的依赖,而非depend-on或者是其他。当A引用B,B引用C,C又引用A就构成了循环引用,也就是我们平时所说的循环依赖了,这里也有不同的情况,bean为单例的,bean为原型的,基于属性构成的循环依赖,基于构造函数参数构成的循环依赖,我们来分别看下这些情况。

2:单例基于属性的循环依赖

2.1:定义3个类

public class SingletonByPropertyA {
    private SingletonByPropertyB singletonByPropertyB;

    public SingletonByPropertyB getSingletonByPropertyB() {
        return singletonByPropertyB;
    }

    public void setSingletonByPropertyB(SingletonByPropertyB singletonByPropertyB) {
        this.singletonByPropertyB = singletonByPropertyB;
    }
}
public class SingletonByPropertyB {
    private SingletonByPropertyC singletonByPropertyC;

    public SingletonByPropertyC getSingletonByPropertyC() {
        return singletonByPropertyC;
    }

    public void setSingletonByPropertyC(SingletonByPropertyC singletonByPropertyC) {
        this.singletonByPropertyC = singletonByPropertyC;
    }
}
public class SingletonByPropertyC {
    private SingletonByPropertyA singletonByPropertyA;

    public SingletonByPropertyA getSingletonByPropertyA() {
        return singletonByPropertyA;
    }

    public void setSingletonByPropertyA(SingletonByPropertyA singletonByPropertyA) {
        this.singletonByPropertyA = singletonByPropertyA;
    }
}

可以看到SingletonByPropertyA引用SingletonByPropertyB,SingletonByPropertyB引用SingletonByPropertyC,SingletonByPropertyC引用SingletonByPropertyA,就构成了循环依赖了。

2.2:定义配置文件

<?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="byPropertyA" class="yudaosourcecode.recyclereference.SingletonByPropertyA">
        <property name="singletonByPropertyB" ref="byPropertyB"/>
    </bean>
    <bean id="byPropertyB" class="yudaosourcecode.recyclereference.SingletonByPropertyB">
        <property name="singletonByPropertyC" ref="byPropertyC"/>
    </bean>
    <bean id="byPropertyC" class="yudaosourcecode.recyclereference.SingletonByPropertyC">
        <property name="singletonByPropertyA" ref="byPropertyA"/>
    </bean>
</beans>

2.3:测试

代码:

@Test
public void testrecyclereference_singleton_field() {
    ClassPathXmlApplicationContext ac
            = new ClassPathXmlApplicationContext("testrecyclereference_singleton_field.xml");
    System.out.println(ac.getBean("byPropertyA"));
    System.out.println(ac.getBean("byPropertyB"));
    System.out.println(ac.getBean("byPropertyC"));
}

运行:

yudaosourcecode.recyclereference.SingletonByPropertyA@7a30d1e6
yudaosourcecode.recyclereference.SingletonByPropertyB@5891e32e
yudaosourcecode.recyclereference.SingletonByPropertyC@cb0ed20

Process finished with exit code 0

3:单例基于构造函数参数的循环依赖

3.1:定义3个类

public class SingletonConstructorArgA {
    public SingletonConstructorArgA(SingletonConstructorArgB singletonConstructorArgB) {}
}
public class SingletonConstructorArgB {

    public SingletonConstructorArgB(SingletonConstructorArgC singletonConstructorArgC) {}
}
public class SingletonConstructorArgC {
    public SingletonConstructorArgC(SingletonConstructorArgA singletonConstructorArgA) {}
}

3.2:定义配置文件

<?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="singletonConstructorArgA" class="yudaosourcecode.recyclereference.SingletonConstructorArgA">
        <constructor-arg index="0" ref="singletonConstructorArgB"/>
    </bean>
    <bean id="singletonConstructorArgB" class="yudaosourcecode.recyclereference.SingletonConstructorArgB">
        <constructor-arg index="0" ref="singletonConstructorArgC"/>
    </bean>
    <bean id="singletonConstructorArgC" class="yudaosourcecode.recyclereference.SingletonConstructorArgC">
        <constructor-arg index="0" ref="singletonConstructorArgA"/>
    </bean>
</beans>

3.3:测试

@Test
public void testrecyclereference_singleton_constructorarg() {
     new ClassPathXmlApplicationContext("testrecyclereference_singleton_constructorarg.xml");
}

运行:

...
Error creating bean with name 'singletonConstructorArgA': 
Requested bean is currently in creation: Is there an unresolvable circular reference?

可以看到因为循环引用依赖报错了,所以可以得出结论,对于单例的由于构造函数参数的引用造成的循环依赖spring不解决,而是直接异常。

4:原型基于属性的循环依赖

4.1:定义3个类

public class PrototypeByPropertyA {
    private PrototypeByPropertyB prototypeByPropertyB;

    public PrototypeByPropertyB getPrototypeByPropertyB() {
        return prototypeByPropertyB;
    }

    public void setPrototypeByPropertyB(PrototypeByPropertyB prototypeByPropertyB) {
        this.prototypeByPropertyB = prototypeByPropertyB;
    }
}
public class PrototypeByPropertyB {
    private PrototypeByPropertyC prototypeByPropertyC;

    public PrototypeByPropertyC getPrototypeByPropertyC() {
        return prototypeByPropertyC;
    }

    public void setPrototypeByPropertyC(PrototypeByPropertyC prototypeByPropertyC) {
        this.prototypeByPropertyC = prototypeByPropertyC;
    }
}
public class PrototypeByPropertyC {
    private PrototypeByPropertyA prototypeByPropertyA;

    public PrototypeByPropertyA getPrototypeByPropertyA() {
        return prototypeByPropertyA;
    }

    public void setPrototypeByPropertyA(PrototypeByPropertyA prototypeByPropertyA) {
        this.prototypeByPropertyA = prototypeByPropertyA;
    }
}

4.2:定义配置文件

<?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="prototypeByPropertyA" class="yudaosourcecode.recyclereference.PrototypeByPropertyA" scope="prototype">
        <property name="prototypeByPropertyB" ref="prototypeByPropertyB"/>
    </bean>
    <bean id="prototypeByPropertyB" class="yudaosourcecode.recyclereference.PrototypeByPropertyB" scope="prototype">
        <property name="prototypeByPropertyC" ref="prototypeByPropertyC"/>
    </bean>
    <bean id="prototypeByPropertyC" class="yudaosourcecode.recyclereference.PrototypeByPropertyC" scope="prototype">
        <property name="prototypeByPropertyA" ref="prototypeByPropertyA"/>
    </bean>
</beans>

4.3:测试

@Test
public void testrecyclereference_prototype_field() {
    ClassPathXmlApplicationContext ac
            = new ClassPathXmlApplicationContext("testrecyclereference_prototype_field.xml");
    System.out.println(ac.getBean("prototypeByPropertyA"));
    System.out.println(ac.getBean("prototypeByPropertyB"));
    System.out.println(ac.getBean("prototypeByPropertyC"));
}

运行:

...
exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'prototypeByPropertyA':
 Requested bean is currently in creation: Is there an unresolvable circular reference?

可以看到报了循环依赖的错误,可以得出结论,对于原型方式的属性引用构成的循环依赖,spring不处理,直接异常。

5:原型基于构造函数的循环依赖

5.1:定义3个类

public class PrototypeByConstructorArgA {
    public PrototypeByConstructorArgA(PrototypeByConstructorArgB prototypeByConstructorArgB) {}
}
public class PrototypeByConstructorArgB {
    public PrototypeByConstructorArgB(PrototypeByConstructorArgC prototypeByConstructorArgC) {}
}
public class PrototypeByConstructorArgC {
    public PrototypeByConstructorArgC(PrototypeByConstructorArgA prototypeByConstructorArgA) {}
}

5.2:定义配置文件

<?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="prototypeByConstructorArgA" class="yudaosourcecode.recyclereference.PrototypeByConstructorArgA" scope="prototype">
        <constructor-arg name="prototypeByConstructorArgB" ref="prototypeByConstructorArgB"/>
    </bean>
    <bean id="prototypeByConstructorArgB" class="yudaosourcecode.recyclereference.PrototypeByConstructorArgB" scope="prototype">
        <constructor-arg name="prototypeByConstructorArgC" ref="prototypeByConstructorArgC"/>
    </bean>
    <bean id="prototypeByConstructorArgC" class="yudaosourcecode.recyclereference.PrototypeByConstructorArgC" scope="prototype">
        <constructor-arg name="prototypeByConstructorArgA" ref="prototypeByConstructorArgA"/>
    </bean>
</beans>

5.3:测试

@Test
public void testrecyclereference_prototype_construstorarg() {
    ClassPathXmlApplicationContext ac
            = new ClassPathXmlApplicationContext("testrecyclereference_prototype_construstorarg.xml");
    System.out.println(ac.getBean("prototypeByConstructorArgA"));
    System.out.println(ac.getBean("prototypeByConstructorArgB"));
    System.out.println(ac.getBean("prototypeByConstructorArgC"));
}

运行:

...snip...
[testrecyclereference_prototype_construstorarg.xml]: 
Cannot resolve reference to bean 'prototypeByConstructorArgA' while setting constructor argument;
 nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'prototypeByConstructorArgA': 
Requested bean is currently in creation: Is there an unresolvable circular reference?

可以看到提示了循环依赖的错误,可以得出结论,对于原型bean基于构造函数引用的循环依赖spring是不处理的,直接异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值