【问题标题】:Circular dependency in Spring By setter injectionSpring中的循环依赖通过setter注入
【发布时间】:2016-10-06 20:21:06
【问题描述】:

考虑以下代码:
这是A类

public class A {

    public A() {
        System.out.println("Creating instance of A");
    }

    private B b;

    public void setB(B b) {
        System.out.println("Setting property b of A instance");
        this.b = b;
    }

}

这里是B类

public class B {

    public B() {
        System.out.println("Creating instance of B");
    }

    private A a;

    public void setA(A a) {
        System.out.println("Setting property a of B instance");
        this.a = a;
    }

}

我们有这个配置文件:

<bean id="a" class="mypackage.A">
    <property name="b" ref="b" />
</bean>

<bean id="b" class="mypackage.B">
    <property name="a" ref="a" />
</bean>

输出:

Creating instance of A
Creating instance of B
Setting property a of B instance
Setting property b of A instance

a 注入b 时,a 尚未完全初始化。

我的问题:
尽管当 'b' 引用 'a' 时 'a' 没有完全初始化,但片刻之后 'a' 将完全初始化。由于“b”引用了“a”,那么“b”将在片刻后指向完全初始化的“a”。 通常给出这种解释是为了显示循环依赖的缺点。 但最终我们遇到了完全初始化的 bean 'a' 和 'b' 相互指向的正常情况。那么,这个例子如何向我们展示了使用循环依赖的缺点呢?

我会引用 spring 文档:

与典型情况(没有循环依赖)不同,循环 bean A 和 bean B 之间的依赖关系强制 bean 之一 在完全初始化之前注入另一个(一个 经典的鸡/蛋场景)

参考:示例取自Circular dependency in spring

【问题讨论】:

  • 问题是什么? Spring确实支持循环依赖
  • 是的,但不建议使用它。他们给出的原因如上所示。我的反驳论点也如上所示。
  • 现在尝试添加一个@PostConstruct 方法,其中A 使用BB 使用A。其中一个会破裂。因为要么 A 在使用前没有完全初始化,要么 B 在使用时没有完全初始化。如果出于任何原因您有一个无副作用的二传手,它也可能会损坏。具有循环依赖会使您的代码变得脆弱,并可能导致运行时出现奇怪的行为(尤其是在启动/初始化代码中)。更不用说根据需要它甚至可能会使编译器感到困惑。

标签: spring


【解决方案1】:

Spring 文档解释了dependency resolution process

不同于典型的情况(有没有循环依赖),一个循环 bean A 和 bean B 之间的依赖关系强制 bean 之一 注入到另一个之前完全初始化自己(一个 经典的鸡/蛋场景)。

bean首先被实例化,然后相互注入。

这就是为什么 Spring 需要一个没有参数的构造函数 ;-)

【讨论】:

  • 为什么不建议循环依赖?为此,一般给出上面的例子。但是,即使 bean 'a' 在一段时间后完全初始化,上面的示例如何向我们展示循环依赖的缺点?
  • 你有什么问题?
  • Bean 'a' 被完全初始化。 Bean 'b' 指向它。在上面的例子中,循环依赖不是障碍。那么,为什么上面的例子被告知要显示循环依赖的缺点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-14
相关资源
最近更新 更多