如何在Spring中解决循环依赖

时间:2016-01-15 04:06:03

标签: java spring

我怎样才能在spring中解决循环依赖。当我们有一个类A依赖于类B而类B依赖于C时所以如何使用spring解决这些问题(基于注释)

4 个答案:

答案 0 :(得分:2)

欢迎o SO。您应该提供PasswordTextBox.wrap(element),让我告诉您:

  

我的问题是假设B级注入A级......

<强> BeanA

package test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class BeanA {

    @Autowired
    BeanB b;

}
  

......而A类是在C级注入的......

package test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class BeanC {

    @Autowired
    BeanA a;

}

而B就像

一样简单

<强> BeanB

package test;

import org.springframework.stereotype.Component;

@Component
public class BeanB {

}

这是我的测试:

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class RefTest {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring.xml");
        BeanC c = ac.getBean(BeanC.class);
        System.out.println("is c null? " + (c == null));
        System.out.println("is c.a null? " + (c.a == null));
        System.out.println("is c.a.b null? " + (c.a.b == null));
    }

}

我的 spring.xml 几乎为空(只有component-scan):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="test" />

</beans>

结果是:

is c null? false
is c.a null? false
is c.a.b null? false

通常,如果注入不起作用,那是因为bean不是使用Spring创建的,而是使用new运算符...

如果您使用不同的详细信息,请使用其他详细信息更新您的问题。

顺便说一句:我同意Ian Mc的说法,这不是循环依赖

答案 1 :(得分:2)

尝试在构造函数中使用@Lazy注释,如下所示:

@Component
public class C {
    private final A a;

    @Autowired
    public C(@Lazy final A a) {
        this.a = a;
    }
}

这使得A bean只在实际需要时初始化,而不是在应用程序启动时才初始化。

答案 2 :(得分:1)

首先让我声称循环依赖是坏的。不管你是否使用Spring。你应该重构你的代码,以便摆脱它们。

现在问题的解决方案:据我所知,只有在使用构造函数注入时,Spring才会无法处理循环依赖。所以,当你让spring通过property-或setter-injection注入这种依赖时,它应该可以工作。

答案 3 :(得分:1)

Rajeev,你所解释的不是循环依赖。您必须创建A,B和C作为Spring Beans,并让Spring管理相关的依赖项。

要清楚,循环依赖是A依赖于B,B依赖于C,但C依赖于A.那么在这种情况下首先要创建什么?您无法创建A,因为尚未创建B.您无法创建B,因为尚未创建C.并且您无法创建C,因为尚未创建A.所以春天停止了。

在你的情况下:A取决于B,B取决于C.那么现在呢? Spring说:我先创建C语言。然后我将创建B,最后我将创建A。

这是可能的,因为Spring将首先创建所有bean定义。然后,当创建bean时,Spring会理解连接,并以正确的顺序构建bean以解决依赖关系。

我创建了一个小型项目,模拟您的状况,以及您如何描述问题,以及稍后您在评论中如何回应。从来没有问题! Spring可以毫无问题地管理您描述的两种情况。我实现了InitialingBean来挂钩创建,以显示创建bean的顺序。

@Component
public class A implements InitializingBean {

@Autowired
private B b;

private String name;

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

@Override
public String toString() {
    return "My name is "+name+"; b name is "+b.getName();
}

@Override
public void afterPropertiesSet() throws Exception {
    System.out.println("Creating A");
    System.out.println("B name="+b.getName());
}

}



@Component
public class B implements InitializingBean {

private String name;

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

@Override
public String toString() {
    return "B [name=" + name + "]";
}

@Override
public void afterPropertiesSet() throws Exception {
    System.out.println("Creating b");
}

}



@Component
public class C implements InitializingBean {

@Autowired
private A a;

private String name;

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

@Override
public String toString() {
    return "My name is "+name+"; a name is "+a.getName();
}

@Override
public void afterPropertiesSet() throws Exception {
    System.out.println("Creating c");
    System.out.println("A name="+a.getName());
}
}