spring @PostConstruct以及循环依赖的bean

@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版权协议,转载请附上原文出处链接和本声明。