Spring:循环依赖,@ PostConstruct和@DependsOn强加的顺序

时间:2015-03-25 16:02:27

标签: java spring

我希望Spring在调用@DependsOn方法时考虑@PostConstruct,但似乎不存在循环(自动连线)依赖关系的情况。

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

我理解这是一个糟糕的设计(实际上,它是非常大的post ...代码库的最小演示),但我期待Spring完成@Autowired字段和然后开始调用生命周期回调,尊重@Autowired,但是当有圆形代表时,Spring似乎忽略了@DependsOn顺序。

Spring版本是4.1.5。

那么,这是我的误解无证件行为还是可以被视为一个Spring bug (或者,也许是功能请求)?

@DependsOn

2 个答案:

答案 0 :(得分:3)

在关于Initialization callbacks的章节中,Spring文档说明了

  

[@PostConstruct和其他方法]允许bean执行   在bean的所有必要属性之后进行初始化工作   由容器设置。

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

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

第二个案例@PostConstruct正在构建beanB时构建。这就是Spring如何解决以下问题

beanA

必须先创建每个实例才能将其注入另一个实例。


如果你摆脱了class A { private B b; } class B { private A a; } ,你会得到相同的行为(但这只是因为类路径扫描的默认排序,这似乎是按字母顺序排列的)。例如,如果您将@DependsOn重命名为BeanA,则BeanZ将首先实例化,然后beanB将被实例化,初始化并返回注入{{1} }}

beanZ实际上只有在你初始化bean之前有你想要的副作用时才是必要的。

答案 1 :(得分:0)

受Sotirios的回答启发并进行了一些调查:

class A {
    private B b;
}

class B {
    private A a;
}

spring要做的是实例化一个ab

然后,它为a执行“设置阶段”。它将设置a.b=b;,然后将在@PostConstruct上调用a方法。

然后为b执行“设置”。它设置b.a=a;,然后在b上调用@PostConstruct方法。

因此,如果您仔细查看,在a的{​​{1}}时,@PostConstruct尚未完全设置。就像... b尚未被分配。

@AutoWiredb.a的{​​{1}}中为空。

显然这是“春天之路”吗?

因此,如果a的{​​{1}}调用b @PostConstruct上的某个方法,则b的循环a尚未分配,因此最终结果(如果tell_me_about_a调用a @PostConstruct的方法是一个类似于

的调用栈
b.tell_me_about_a

但是,在a的{​​{1}} a期间,实例已完全启动,并且缺少其NullPointerException # calling some A method someLineOfB somePostConstructMethodOfA 的实例,因此b不会是NullPointerException。令人困惑...

@PostConstruct可以更改某些顺序。但似乎与expect的顺序相反。 我认为您是对的,因为它是圆形的,您不能依赖@DependsOn [?],因为它可以按预期的方式运行(如果没有按预期的顺序运行PostConstruct,那么对我来说这就像一个错误。

您可以通过添加spring logging来看到这种行为,然后您会看到诸如b.a demo

之类的消息

可以解决的方法:

在PostConstruct期间请小心使用注入依赖项的方法。或不打。

完全使用弹簧连接的构造函数参数代替@AutoWired。在这种情况下,弹簧不允许圆形。无论如何你可能想要...

以相反的顺序使用@DependsOn吗?什么?...