我希望 Spring 在调用 @DependsOn 方法时考虑 @PostConstruct ,但似乎在存在循环(自动连接)依赖项时情况并非如此。

考虑两个 bean(下面的代码), BeanB @DependsOn BeanA 。当字段 BeanA#b 将其 @Autowired 注释掉时,后构造方法按预期顺序调用:首先是 A,然后是 B。但是由于 @Autowired 对 A 有效,我先调用了 B 的 post ,然后是 A 的 post

我知道这是一个糟糕的设计(实际上,它是非常大的 @Autowired ... 代码库的最小演示),但我期待 Spring 完成 @Autowired 字段的注入(inject),然后开始调用生命周期回调,尊重 @DependsOn ,但 Spring 似乎当有循环 deps 时忽略 @DependsOn 顺序。

Spring 版本是 4.1.5。

那么,这是 我的误解 未记录的行为 还是可以将 视为 Spring 错误 (或者,可能是功能请求)?

@Component
class BeanA {

    // @Autowired
    private BeanB b;

    void f() {
        System.out.println(this);
    }

    @PostConstruct
    void post() {
        System.out.println("A done");
    }

    @Override
    public String toString() {
        return "Bean{" +
                "b=" + (b == null ? null : b.getClass()) +
                '}';
    }
}
// ---------------------
@Component
@DependsOn("beanA")
class BeanB {

    @Autowired
    private BeanA a;

    void f() {
        System.out.println(this);
    }

    @PostConstruct
    void post() {
        System.out.println("B done");
    }

    @Override
    public String toString() {
        return "BeanB{" +
                "a=" + (a == null ? null : a.getClass()) +
                '}';
    }
}

最佳答案

在关于 Initialization callbacks 的章节中,Spring 文档指出



使用您的注释代码,会发生以下情况: beanA 被实例化并保存。容器看到所有必要的属性都已设置,并调用 init ( @PostConstruct ) 方法。然后它转到 beanB ,它初始化,保存,查看 @Autowired ,检索保存的 beanA ,注入(inject)它,运行 beanB@PostConstruct ,因为它的所有属性都已设置。

在您未注释的代码中,您有一个循环依赖的情况。 beanA 首先被实例化并被保存。容器注意到它有一个 BeanB 类型的注入(inject)目标。要执行此注入(inject),它需要 beanB bean。因此它实例化 bean,保存它,看到它依赖于 beanA 作为注入(inject)目标。它检索 beanA (之前保存的),注入(inject)它,然后 beanB 的属性全部设置并调用其 @PostConstruct 方法。最后,这个初始化的 beanB bean 被注入(inject)到 beanA 中,然后调用其 @PostConstruct 方法,因为它的所有属性都已设置。

第二个案例 beanB 正在构建,而 beanA 正在构建。这就是Spring如何解决以下问题

class A {
    private B b;
}

class B {
    private A a;
}

必须先创建每个实例,然后才能将其注入(inject)另一个。

如果你去掉 @DependsOn ,你会得到相同的行为(但仅仅是因为类路径扫描的默认顺序,这似乎是按字母顺序排列的)。例如,如果您将 BeanA 重命名为 BeanZ ,则 beanB 将首先被实例化,然后 beanZ 将被实例化、初始化并返回以注入(inject)到 beanB 中。
@DependsOn 只有在您希望在 bean 初始化之前发生的副作用时才真正需要。

关于java - Spring:循环依赖,@PostConstruct 和@DependsOn 强加的顺序,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29260676/

10-12 04:35