1. 概述

本文将介绍如何在 Spring 中为静态字段注入配置值。

这是一个看似简单但容易踩坑的问题:你可能理所当然地认为 @Value 能直接注入静态字段,结果运行时却发现值为 null。✅ 本文就来解决这个常见误区。

2. 问题背景

假设我们有一个配置文件 application.properties,内容如下:

name=Inject a value to a static field

我们希望把这个配置值注入到某个类的静态字段中。第一反应可能是这样写:

@Component
public class StaticPropertyHolder {

    @Value("${name}")
    private static String STATIC_NAME_INJECTED_ON_FIELD;

    public static String getStaticNameInjectedOnField() {
        return STATIC_NAME_INJECTED_ON_FIELD;
    }
}

看起来很合理,对吧?但运行测试会发现:

assertNull(StaticPropertyHolder.getStaticNameInjectedOnField());

⚠️ 结果是 null!根本没注入成功。

原因很简单:Spring 的 @Value 注解不支持直接作用于静态字段
这是因为 Spring 的依赖注入(DI)机制基于 Bean 实例,而静态字段属于类层级,不属于任何实例,Spring 容器无法通过常规方式赋值。

3. 正确解决方案

解决思路很简单粗暴:@Value 放在 setter 方法上,通过方法注入来间接赋值静态字段

具体实现如下:

@Component
public class StaticPropertyHolder {

    private static String STATIC_NAME;

    @Value("${name}")
    public void setStaticName(String name) {
        STATIC_NAME = name;
    }

    public static String getStaticName() {
        return STATIC_NAME;
    }
}

✅ 测试验证:

assertEquals("Inject a value to a static field", StaticPropertyHolder.getStaticName());

结果正确,注入成功!

原理说明

  • Spring 在初始化 Bean 时,会扫描带有 @Value 的方法(包括 setter)
  • 当发现 @Value("${name}") 注解的方法时,Spring 会将解析后的配置值作为参数传入
  • 方法内部将该值赋给静态字段,完成“间接注入”

📌 关键点:

  • @Value 仍然作用在实例方法上(符合 Spring DI 规范)
  • 静态字段通过方法调用被赋值,绕过了直接注入的限制
  • 该方法在 Bean 初始化阶段执行,保证静态字段在后续使用前已被正确赋值

💡 小贴士:即使这个 setter 方法没有被外部调用,Spring 容器也会在 DI 阶段自动触发它,完全无需手动干预。

4. 总结

  • ❌ 不要尝试在静态字段上直接使用 @Value
  • ✅ 正确做法:将 @Value 注解放在一个 public 的 setter 方法上,通过方法体内赋值静态字段
  • ⚠️ 该方法必须是 public,否则 Spring 可能无法访问(取决于配置和代理方式)

这种写法虽然多了一层间接,但在实际项目中稳定可靠,是目前最简单且被广泛采用的方案。

示例代码已上传至 GitHub:https://github.com/baeldung/spring-di-2


原始标题:Injecting a Value in a Static Field in Spring | Baeldung