我希望 Spring@DependsOn在调用@PostConstruct方法时考虑到这一点,但似乎在存在循环(自动连接)依赖项时情况并非如此。
考虑两个 bean(下面的代码),BeanB @DependsOn BeanA. 当现场BeanA#b有它@Autowired注释掉,后期构造方法的调用预期顺序:先A,然后B.但随着@Autowired在甲效果,我有B的post第一调用,那么A的post。
我知道这是一个糟糕的设计(实际上,它是非常大的@Autowired...代码库的最小演示),但我期待 Spring 完成@Autowired字段的注入,然后开始调用生命周期回调,尊重@DependsOn,但 Spring 似乎忽略了@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()) +
'}';
}
}
Run Code Online (Sandbox Code Playgroud)
在关于初始化回调的章节中,Spring 文档指出
[
@PostConstruct和其他方法] 允许 bean 在容器设置了 bean 的所有必要属性后执行初始化工作。
使用您注释的代码,会发生以下情况:beanA实例化并保存。容器看到所有必需的属性都已设置,并调用 init ( @PostConstruct) 方法。然后它会去beanB初始化、保存、查看@Autowired、检索保存的beanA、注入它、运行beanB的,@PostConstruct因为它的所有属性都已设置。
在您未注释的代码中,您有一个循环依赖的情况。beanA首先被实例化并被保存。容器注意到它有一个类型为 的注入目标BeanB。要执行此注入,它需要beanBbean。因此它实例化 bean,保存它,看到它依赖于beanA作为注入目标的 a。它检索beanA(之前保存的),注入它,然后beanB设置所有属性并@PostConstruct调用其方法。最后,这个初始化的beanBbean 被注入到 中beanA,@PostConstruct然后调用它的方法,因为它的所有属性都已设置。
这第二个案例beanB正在构建时beanA正在构建。这就是Spring如何解决以下问题
class A {
private B b;
}
class B {
private A a;
}
Run Code Online (Sandbox Code Playgroud)
必须先创建每个实例,然后才能将其注入另一个。
如果您去掉@DependsOn,您将获得相同的行为(但仅仅是因为类路径扫描的默认顺序,这似乎是按字母顺序排列的)。例如,如果您重命名BeanA为BeanZ,beanB将首先实例化,然后beanZ将被实例化、初始化并返回以注入到 中beanB。
@DependsOn 只有当您希望在 bean 初始化之前发生副作用时才真正需要。
| 归档时间: |
|
| 查看次数: |
3921 次 |
| 最近记录: |