You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring注解执行顺序解析:Spring Boot中@Value注入与成员变量初始化顺序疑问

Spring Boot属性注入与成员初始化顺序问题解答

咱们先直接说结论:@Value的属性注入不会在list成员初始化之前完成,你的代码会出现问题——要么编译报错(因为Collections.unmodifiableList需要传入集合而非单个参数),要么初始化后的list里是两个null值,完全达不到预期效果。

为什么会这样?得从Java类初始化+Spring Bean生命周期两个层面来看

1. Java对象实例化的固有顺序

当Spring创建ConfigurationM的Bean时,首先会执行Java对象的实例化流程:

  • 先初始化所有成员变量的默认值或显式赋值(也就是你这里的private List<String> list = Collections.unmodifiableList(propA, propB);)
  • 然后调用类的构造函数(如果有自定义构造的话)

这个阶段里,propA和propB还没被Spring注入值,都是默认的null,所以你试图用它们初始化list的时候,自然拿不到配置文件里的属性值。

2. Spring依赖注入的时机

Spring的属性注入(比如@Value、@Autowired)是在对象实例化完成之后才进行的。也就是说,顺序是:

成员变量初始化 → 构造函数执行 → Spring注入@Value属性 → Bean初始化完成

所以你的list初始化步骤走在了注入前面,自然拿不到正确的属性值。

怎么解决这个问题?给你两种靠谱的方案

方案一:用@PostConstruct延迟list初始化

@PostConstruct注解标注的方法会在Spring完成所有属性注入后执行,刚好适合用来初始化依赖注入属性的list:

@Getter @Setter @ConfigurationProperties
public class ConfigurationM{
    @Value("${propA}")
    private String propA;
    @Value("${propB}")
    private String propB;
    private List<String> list;

    @PostConstruct
    public void initList() {
        // 先把propA、propB转成集合,再包装成不可变列表
        this.list = Collections.unmodifiableList(Arrays.asList(propA, propB));
    }
}

方案二:规范使用@ConfigurationProperties(更推荐)

你已经加了@ConfigurationProperties注解,其实完全可以不用@Value,直接通过配置前缀绑定属性,甚至直接在配置文件里定义list:

  1. 配置文件(application.properties)里添加:
my-config.propA=value-from-config-A
my-config.propB=value-from-config-B
# 如果你想直接定义list的话
# my-config.list[0]=value-from-config-A
# my-config.list[1]=value-from-config-B
  1. 修改配置类:
@Getter @Setter
@ConfigurationProperties(prefix = "my-config") // 指定配置前缀
public class ConfigurationM{
    private String propA;
    private String propB;
    private List<String> list;

    // 如果list是propA和propB的组合,还是用@PostConstruct生成
    @PostConstruct
    public void initList() {
        this.list = Collections.unmodifiableList(Arrays.asList(propA, propB));
    }
}

这种方式更符合Spring Boot配置绑定的规范,也避免了@Value和@ConfigurationProperties混用的潜在问题。

最后再梳理一遍Spring Bean的核心生命周期顺序,帮你记牢

    1. Bean实例化(执行成员变量初始化 → 执行构造函数)
    1. Spring完成属性注入(@Value、@Autowired等)
    1. 执行@PostConstruct标注的初始化方法
    1. Bean进入就绪状态,可以被应用程序使用
    1. 容器关闭时,执行@PreDestroy标注的销毁方法

内容的提问来源于stack exchange,提问作者Abhinav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 09:22:35