什么是循环依赖
Bean之间互相依赖,并最终形成了闭环。
自我依赖
@Component
public class C {
@Autowired
private C c;
}
互相依赖
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
循环依赖使用示例
属性注入
属性的注入通过@Autowired方式注入
@Component
public static class AttributeDependOnB {
@Autowired
AttributeDependOnA attributeDependOnA;
public AttributeDependOnA getAttributeDependOnA() {
return attributeDependOnA;
}
}
@Component
public static class AttributeDependOnA {
@Autowired
AttributeDependOnB attributeDependOnB;
public AttributeDependOnB getAttributeDependOnB() {
return attributeDependOnB;
}
}
<!-- 需要开启包扫描 -->
<context:component-scan base-package="com.ldh"/>
可以正常注入。
setter注入(依赖自身)
public static class DependOnSelfEntity {
DependOnSelfEntity dependOnSelfEntity;
public DependOnSelfEntity getDependOnSelfEntity() {
return dependOnSelfEntity;
}
public void setDependOnSelfEntity(DependOnSelfEntity dependOnSelfEntity) {
this.dependOnSelfEntity = dependOnSelfEntity;
}
}
<bean id="dependOnSelf" class="com.ldh.entity.CircularDependencyTestEntity$DependOnSelfEntity">
<property name="dependOnSelfEntity" ref="dependOnSelf"/>
</bean>
可以正常注入。
setter注入(互相依赖)
public static class SetterDependOnA {
SetterDependOnB dependOnB;
public SetterDependOnA() {
}
public SetterDependOnA(SetterDependOnB dependOnB) {
this.dependOnB = dependOnB;
}
public SetterDependOnB getDependOnB() {
return dependOnB;
}
public void setDependOnB(SetterDependOnB dependOnB) {
this.dependOnB = dependOnB;
}
}
public static class SetterDependOnB {
SetterDependOnA dependOnA;
public SetterDependOnB() {
}
public SetterDependOnB(SetterDependOnA dependOnA) {
this.dependOnA = dependOnA;
}
public SetterDependOnA getDependOnA() {
return dependOnA;
}
public void setDependOnA(SetterDependOnA dependOnA) {
this.dependOnA = dependOnA;
}
}
可以成功注入。
构造器注入
public static class ConstructorDependOnA {
ConstructorDependOnB constructDependB;
public ConstructorDependOnA() {
}
public ConstructorDependOnA(ConstructorDependOnB constructDependB) {
this.constructDependB = constructDependB;
}
public ConstructorDependOnB getConstructDependB() {
return constructDependB;
}
}
public static class ConstructorDependOnB {
ConstructorDependOnA constructDependA;
public ConstructorDependOnB() {
}
public ConstructorDependOnB(ConstructorDependOnA constructDependA) {
this.constructDependA = constructDependA;
}
public ConstructorDependOnA getConstructDependA() {
return constructDependA;
}
}
<bean id="constructorDependOnB" class="com.ldh.entity.CircularDependencyTestEntity$ConstructorDependOnB">
<constructor-arg ref="constructorDependOnA"/>
</bean>
<bean id="constructorDependOnA" class="com.ldh.entity.CircularDependencyTestEntity$ConstructorDependOnA">
<constructor-arg ref="constructorDependOnB"/>
</bean>
测试代码
@Test
public void setterCircularDependency(){
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("circularDependency.xml");
CircularDependencyTestEntity.SetterDependOnA dependOnA = applicationContext.getBean(CircularDependencyTestEntity.SetterDependOnA.class);
CircularDependencyTestEntity.SetterDependOnB dependOnB = applicationContext.getBean(CircularDependencyTestEntity.SetterDependOnB.class);
System.out.println(format("dependOnA:%s",dependOnA));
System.out.println(format("dependOnA.dependOnB:%s",dependOnA.getDependOnB()));
System.out.println(format("dependOnB:%s",dependOnB));
System.out.println(format("dependOnB.dependOnA:%s",dependOnB.getDependOnA()));
}
报如下错误:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'constructorDependOnB': Requested bean is currently in creation: Is there an unresolvable circular reference?
@Configuration方式测试
@Configuration
public static class BeanCircularDependencyConfig {
@Bean
public CircularDependencyTestEntity.SetterDependOnB beanCircularDependOnB(){
CircularDependencyTestEntity.SetterDependOnB dependOnB = new CircularDependencyTestEntity.SetterDependOnB();
dependOnB.setDependOnA(beanCircularDependOnA());
return dependOnB;
}
@Bean
public CircularDependencyTestEntity.SetterDependOnA beanCircularDependOnA() {
CircularDependencyTestEntity.SetterDependOnA dependOnA = new CircularDependencyTestEntity.SetterDependOnA();
dependOnA.setDependOnB(beanCircularDependOnB());
return dependOnA;
}
}
@Test
public void ConfigurationCircularDependency(){
AnnotationConfigApplicationContext applicationContext= new AnnotationConfigApplicationContext();
//注册@Configuration配置类
applicationContext.register(BeanCircularDependencyConfig.class);
//必须refresh()
applicationContext.refresh();
CircularDependencyTestEntity.SetterDependOnA dependOnA = applicationContext.getBean("beanCircularDependOnA",CircularDependencyTestEntity.SetterDependOnA.class);
CircularDependencyTestEntity.SetterDependOnB dependOnB = applicationContext.getBean("beanCircularDependOnB",CircularDependencyTestEntity.SetterDependOnB.class);
System.out.println(format("dependOnA:%s",dependOnA));
System.out.println(format("dependOnA.dependOnB:%s",dependOnA.getDependOnB()));
System.out.println(format("dependOnB:%s",dependOnB));
System.out.println(format("dependOnB.dependOnA:%s",dependOnB.getDependOnA()));
}
报错:
java.lang.NoClassDefFoundError: org.springframework.beans.FatalBeanException
通过打断点可以发现,Spring陷入死循环,最终报上面的错误
- #beanCircularDependOnB()
- #beanCircularDependOnA()
- #beanCircularDependOnB()
- #beanCircularDependOnA()
- ......
说明@Configuration方式无法解决循环依赖。
通过增加@Lazy注解也无法解决,报相同的错误
setter注入和构造器注入同时存在的情况
Spring在创建Bean时,默认会根据自然排序进行创建,所以A会先于B创建
- AB相互依赖 - A为setter,B为构造器:A的半成品加入缓存,然后创建B实例时,即可通过构造器注入完成B的构造
- AB相互依赖-A为构造器,B为setter:A在创建时需要注入B;创建B时,因为通过构造器注入,A没有用到缓存,创建B失败,导致构造失败
@DependsOn循环依赖
@DependOn注解会显示的指定Bean的依赖关系。但是,如果Bean之间如果通过@DependsOn注解形成了循环依赖的闭环,会抛出异常。
示例代码
@Configuration
public static class DependsOnConf {
@DependsOn("getDependOnEntityB")
@Bean
public DependsOnEntityA getDependOnEntityA() {
return new DependsOnEntityA();
}
@DependsOn("getDependOnEntityA")
@Bean
public DependsOnEntityB getDependOnEntityB() {
return new DependsOnEntityB();
}
}
错误日志
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getDependOnEntityB' defined in com.ldh.DependsOnTest$DependsOnConf: Circular depends-on relationship between 'getDependOnEntityB' and 'getDependOnEntityA'
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:305)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
代码位置
// AbstractBeanFactory
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
.....
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 检查Bean的依赖或传递性依赖的情况
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
.....
}