处理CDI中的循环依赖

Pat*_*tan 7 java dependency-injection cdi

我有这样的情况.我看不到任何错误,但我没有得到我的结果.

@ApplicationScoped
public class A {

    private B b;


    @Inject
    public A(B b) {
        this.b = b;
    }
}

@Singleton
public class B {

    private A a;


    @Inject
    public B(A a) {
        this.a = a;
    }
}
Run Code Online (Sandbox Code Playgroud)

这种类型的依赖注入是错误的吗?

谁能帮我这个.

And*_*dré 5

我会避免这种循环依赖,这样做有几个原因。

评论这篇文章

凌乱的构造函数是一个标志。它警告我,我的班级正在成为一个庞然大物,它是各行各业的杰作,却一无所获。换句话说,一个凌乱的构造函数实际上是一件好事。如果我觉得一个类的构造函数太乱了,我知道是时候做点什么了。

这个

您会发现类 A 需要 B 的实例而 B 需要 A 的实例的情况。这是循环依赖的典型情况,显然很糟糕。根据我的经验,解决方案是让 B 成为 A 的一部分,当两者非常依赖以至于它们真的应该是一个类时。更常见的是,至少还有一个 C 类隐藏在那里,因此 B 不需要 A 而只需要 C。

正如奥利弗·格克( Oliver Gerke)评论的那样

尤其是构造函数注入实际上可以防止您引入循环依赖。如果你确实引入了它们,你本质上就是把两方合二为一,因为你不能真正改变一方而不冒破坏另一方的风险,这在任何情况下都是一种设计味道。

这是我可能会做的一个小例子。

public class A {

    private B b;

    @Autowired
    public A(B b) {
        this.b = b;
    }

    public void doSomeWork() {
        // WORK
    }

    public void doSomeWorkWithB() {
        b.doSomeWork();
    }
}

public class B {

    private A a;

    @Autowired
    public B(A a) {
        this.a = a;
    }

    public void doSomeWork() {
        // WORK
    }

    public void doSomeWorkWithA() {
        a.doSomeWork();
    }

}
Run Code Online (Sandbox Code Playgroud)

重构后它可能看起来像这样。

public class A {

    private C c;

    @Autowired
    public A(C c) {
        this.c = c;
    }

    public void doSomeWork() {
        // WORK
    }

    public void doSomeWorkWithC() {
        c.doSomeWorkThatWasOnA();
    }

}

public class B {

    private C c;

    @Autowired
    public B(C c) {
        this.c = c;
    }

    public void doSomeWork() {
        // WORK
    }

    public void doSomeWorkWithC() {
        c.doSomeWorkThatWasOnB();
    }

}

public class C {

    public void doSomeWorkThatWasOnB() {
        // WORK

    }

    public void doSomeWorkThatWasOnA() {
        // WORK
    }

}
Run Code Online (Sandbox Code Playgroud)


Har*_*ann 5

引用CDI 规范 1.2 的第 5 节:

容器需要支持 bean 依赖图中的循环,其中至少有一个 bean 参与每个循环依赖关系链具有正常范围,如正常范围和伪范围中所定义。容器不需要支持循环依赖链,其中每个参与链的 bean 都有一个伪作用域。

ApplicationScoped 是一个正常的范围,所以这个循环应该可以工作。

在您的示例中,类A不能被代理,因为它缺少零参数构造函数。添加此构造函数(可能具有受保护或包可见性),您的示例部署没有问题。