@PostConstruct
/**
* The <code>PostConstruct</code> annotation is used on a method that
* needs to be executed after dependency injection is done to perform
* any initialization. This method must be invoked before the class
* is put into service.
* ...
* /
一般认为, 在调用到PostConstruct的时候,PostConstruct所依赖的bean都应该是已经初始化完成。但是在有循环依赖的情况下。并不成立。
Example code
Dog.java
@Component
@Slf4j
public class Dog {
private Cat cat;
public Dog() {
log.info("constructing dog");
}
public Cat getCat() {
return cat;
}
@Autowired
public void setCat(Cat cat) {
log.info("setting {} within dog. {}, {}", cat, cat.getDog(), this);
this.cat = cat;
}
@PostConstruct
public void afterInit() {
log.info("dog complete. {}, {}", cat.getDog(), this);
}
}
Cat.java
@Component
@Slf4j
public class Cat {
private Dog dog;
public Dog getDog() {
return dog;
}
public Cat() {
log.info("constructing cat");
}
@Autowired
public void setDog(Dog dog) {
this.dog = dog;
log.info("setting {} within Cat. {}, {}", dog, dog.getCat(), this);
}
@PostConstruct
public void afterInit() {
log.info("cat complete. {}, {}", dog.getCat(), this);
}
}
在每个log.info打断点可以清晰看到初始化过程.
2021-12-09 10:42:30.319 INFO 40165 --- [ main] com.github.chengpan.taskd.animals.Cat : constructing cat
2021-12-09 10:42:30.321 INFO 40165 --- [ main] com.github.chengpan.taskd.animals.Dog : constructing dog
2021-12-09 10:42:30.322 INFO 40165 --- [ main] com.github.chengpan.taskd.animals.Dog : setting com.github.chengpan.taskd.animals.Cat@36dafa24 within dog. null, com.github.chengpan.taskd.animals.Dog@2b098563
2021-12-09 10:42:30.322 INFO 40165 --- [ main] com.github.chengpan.taskd.animals.Dog : dog complete. null, com.github.chengpan.taskd.animals.Dog@2b098563
2021-12-09 10:42:30.322 INFO 40165 --- [ main] com.github.chengpan.taskd.animals.Cat : setting com.github.chengpan.taskd.animals.Dog@2b098563 within Cat. com.github.chengpan.taskd.animals.Cat@36dafa24, com.github.chengpan.taskd.animals.Cat@36dafa24
2021-12-09 10:42:30.323 INFO 40165 --- [ main] com.github.chengpan.taskd.animals.Cat : cat complete. com.github.chengpan.taskd.animals.Cat@36dafa24, com.github.chengpan.taskd.animals.Cat@36dafa24
说明
spring在遇到Cat component的时候,首先调用了Cat的构造器,然后打算给Cat注入Dog component, 于是转而去初始化Dog,首先是Dog的constructor, 然后是Dog的setter,这时候给Dog注入Cat的component是还在初始化中的, Cat的field字段还是null。尽管如此, Dog依旧玩成了初始化,并且调用了PostConstruct回掉。注意此时Cat的dog字段其实还是处在初始化中的,并不能用。
结论
- @PostConstruct只能保证依赖注入已完成,并不能保证注入的依赖是完全初始化好的。
- 尽量使用Constructor注入
版权声明:本文为weixin_45594127原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。