我有以下三个类(class) -
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@Component
public class Test {
@Autowired
Test2 test2;
@PostConstruct
public void sayHi(){
System.out.println("Hello World");
test2.SayHello();
}
public void printMe(){
System.out.println("print me is called in Bean B");
}
}
@Component
public class Test2 {
@Autowired
Test test;
@PostConstruct
public void SayHello(){
System.out.println("Test2");
test.sayHi();
}
}
现在这个抛出异常 -
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'test2': Invocation of init method failed; nested exception is java.lang.NullPointerException
但是,如果我按如下方式更改 Test2 类 -
@Component
public class Test2 {
@Autowired
Test test;
@PostConstruct
public void SayHello(){
System.out.println("Test2");
test.printMe();
}
}
这个有效。如果它必须失败,为什么这两种情况都没有失败? 或者如果它必须成功,为什么在这两种情况下都没有成功?
使用 Autowiring 和后构造函数进行 Spring 初始化是如何工作的?
最佳答案
Spring实例化bean并根据它们的关系为它们注入(inject)依赖。
Spring 保证声明的 bean 在调用其注释为 @PostConstruct
的方法之前将注入(inject)/设置所有依赖项。
这里是bean之间的关系:
Test --uses--> Test2
Test2 --uses--> Test
这里是如何工作的:
1) Spring 实例化一个 bean,然后实例化另一个 bean,而不注入(inject)它们的依赖项。到目前为止,顺序并不重要。
2) Spring 为第一个 bean 注入(inject)依赖项。由于此处的依赖关系是双向的,Spring 可以任意决定首先处理哪个 bean。在您的情况下,根据您的错误,Spring 首先处理 Test2
。
3) Spring 在设置其依赖关系后调用 Test2
bean 的 @PostConstruct
方法。
您定义的方法调用使用依赖项字段的 Test
bean 的方法 (Test2 test2
)。
但由于该 bean 的依赖关系尚未设置,
该字段为空,访问它会触发 NPE。
在您的工作案例中,您从 Test2
调用不引用其依赖项字段的 Test
方法。
请注意,通常不建议使用循环依赖。以下是它可能产生的问题的说明。
当您无法删除它们时,您至少应该避免在 @PostConstruct
方法中调用另一个 bean,因为它会破坏容器在初始化期间打破循环所完成的工作。
关于java - Spring Boot Autowired 和 Post Construct 如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60225433/