Spring:在 @PostConstruct 中设置其他 Bean 中变量可能引发的问题


#Spring#


为什么?因为可能出现以为有值,但实际无值的情况。

用一个例子具体来说明:

示例

Bean01.java

package demo.bean;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class Bean01 {

    @Autowired
    private Bean03 bean03;

    public void process() {
        System.out.println("Bean01.process 获取 bean03.data 值: " + bean03.getData());
    }

    @PostConstruct
    private void ps() {
        System.out.println("Bean01 在 PostConstruct 中获取 bean03.data 值: " + bean03.getData());
    }

}

Bean02.java

package demo.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class Bean02 {

    @Autowired
    private Bean03 bean03;

    @PostConstruct
    private void ps() {
        System.out.println("Bean02 在 PostConstruct 中设置 bean03.data 值");
        bean03.setData("你好");
    }

}

Bean03.java

package demo.bean;

import org.springframework.stereotype.Component;


@Component
public class Bean03 {

    private String data;

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}

Main.java

package demo;

import demo.bean.Bean01;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(Main.class);
        Bean01 bean01 = ctx.getBean(Bean01.class);
        bean01.process();
    }

}

执行结果与分析

运行 Main 类,输出:

Bean01 在 PostConstruct 中获取 bean03.data 值: null
Bean02 在 PostConstruct 中设置 bean03.data 值
Bean01.process 获取 bean03.data 值: 你好

注意,第1行的输出,就是以为有值,实际无值(值为 null)的情况,在调用 process 构造函数时,才有值。

为什么执行 Bean01 在 @PostConstruct 修饰的 ps 函数时,未获取到值?

我们先看下依赖关系:

 Bean01    Bean02
  \           /
   \         /
    \       /
      Bean03

Bean01 和 Bean02 无直接依赖,只是共同依赖了 Bean03 。按照命名升序, Bean01 的 @PostContruct 会比 Bean02 的 @PostContruct 先执行,自然获取不到值

为什么执行 Bean01 的 process 方法时,获取到了值?

因为此时 spring 容器已经初始化完成,所有的 @PostContruct 都已经执行完了。

那么,如何让Bean01 在 @PostConstruct 修饰的 ps 函数时,获取到值 ?

让 Bean02 比 Bean01先初始化完成就行。比如用显式声明 Bean01 依赖 Bean02:

// 省略部分内容
import org.springframework.context.annotation.DependsOn;

@Component
@DependsOn("bean02")
public class Bean01 {

此时执行 Main 类,输出:

Bean02 在 PostConstruct 中设置 bean03.data 值
Bean01 在 PostConstruct 中获取 bean03.data 值: 你好
Bean01.process 获取 bean03.data 值: 你好

虽然解决了,但是不建议这样做。因为 在 @PostConstruct 设置其他 Bean 中的变量 本身就不是一个好的实践。


( 本文完 )