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

Spring Boot 2.5.5中@Value注入静态变量返回Null问题求助

Spring @Value注入静态变量为空的问题

尝试通过Spring @Value注解将配置属性注入到静态变量中,但获取到的均为Null值,多种配置方案都无效,此前功能运行正常,不清楚哪项改动导致故障。

问题代码

Java类代码

@Component
@ConditionalOnProperty(prefix = "studioghibli", name = "get")
public class StudioGhibliRestService {

    @Value("${studioghibli.basepath}")
    private static String BASE_PATH;

    @Value("${studioghibli.path}")
    private static String PATH;

    @Value("${studioghibli.protocol:http}")
    private static String PROTOCOL;

    @Value("${studioghibli.host}")
    private static String HOST;

    private static String BASE_URI = PROTOCOL.concat("://").concat(HOST).concat(BASE_PATH).concat(PATH);

    @Autowired
    StudioGhibliRestConnector connector;

    public List<StudioGhibliFilmDTO> findAllFilms() throws SipadContenziosoInternalException {
        var response = connector.doGet(BASE_URI, null, null);
        if (!response.getStatusCode().is2xxSuccessful() || !response.hasBody()) {
            throw new SipadContenziosoInternalException(Errore.INTERNAL_REST_ERROR, "FindAll(), microservizio ".concat(BASE_URI), null);
        }
        return (List<StudioGhibliFilmDTO>) response.getBody();
    }

}

该类标注了@Component注解(作为Service层用于业务逻辑中的REST调用),同时标注了@ConditionalOnProperty注解。启动时调试显示PROTOCOL值为Null,直接触发空指针异常。

配置文件(application-dev.properties)

studioghibli.get
studioghibli.protocol=https
studioghibli.host=ghibliapi.herokuapp.com
studioghibli.basepath=/
studioghibli.path=/films

问题原因

Spring的依赖注入是针对实例对象的,@Value注解无法直接作用于静态变量——静态变量属于类而非实例,Spring在创建类实例、完成依赖注入之前,静态变量就已经完成了初始化(比如代码中的BASE_URI会在类加载时就执行拼接,此时所有静态变量还未被注入值,必然为Null)。

解决方案

方案1:通过实例变量接收注入,初始化阶段赋值给静态变量

利用@PostConstruct注解,在实例初始化完成后,将注入到实例变量的值赋值给静态变量,再拼接BASE_URI:

@Component
@ConditionalOnProperty(prefix = "studioghibli", name = "get")
public class StudioGhibliRestService {

    private static String BASE_PATH;
    private static String PATH;
    private static String PROTOCOL;
    private static String HOST;
    private static String BASE_URI;

    @Value("${studioghibli.basepath}")
    private String basePath;

    @Value("${studioghibli.path}")
    private String path;

    @Value("${studioghibli.protocol:http}")
    private String protocol;

    @Value("${studioghibli.host}")
    private String host;

    @Autowired
    StudioGhibliRestConnector connector;

    @PostConstruct
    public void init() {
        BASE_PATH = basePath;
        PATH = path;
        PROTOCOL = protocol;
        HOST = host;
        BASE_URI = PROTOCOL.concat("://").concat(HOST).concat(BASE_PATH).concat(PATH);
    }

    public List<StudioGhibliFilmDTO> findAllFilms() throws SipadContenziosoInternalException {
        var response = connector.doGet(BASE_URI, null, null);
        if (!response.getStatusCode().is2xxSuccessful() || !response.hasBody()) {
            throw new SipadContenziosoInternalException(Errore.INTERNAL_REST_ERROR, "FindAll(), microservizio ".concat(BASE_URI), null);
        }
        return (List<StudioGhibliFilmDTO>) response.getBody();
    }

}

方案2:通过实例setter方法注入静态变量

为每个静态变量编写非静态的setter方法,并在setter上添加@Value注解,同时在所有值注入完成后更新BASE_URI:

@Component
@ConditionalOnProperty(prefix = "studioghibli", name = "get")
public class StudioGhibliRestService {

    private static String BASE_PATH;
    private static String PATH;
    private static String PROTOCOL;
    private static String HOST;
    private static String BASE_URI;

    @Autowired
    StudioGhibliRestConnector connector;

    @Value("${studioghibli.basepath}")
    public void setBasePath(String basePath) {
        BASE_PATH = basePath;
        updateBaseUri();
    }

    @Value("${studioghibli.path}")
    public void setPath(String path) {
        PATH = path;
        updateBaseUri();
    }

    @Value("${studioghibli.protocol:http}")
    public void setProtocol(String protocol) {
        PROTOCOL = protocol;
        updateBaseUri();
    }

    @Value("${studioghibli.host}")
    public void setHost(String host) {
        HOST = host;
        updateBaseUri();
    }

    private void updateBaseUri() {
        // 确保所有变量都已注入后再拼接
        if (PROTOCOL != null && HOST != null && BASE_PATH != null && PATH != null) {
            BASE_URI = PROTOCOL.concat("://").concat(HOST).concat(BASE_PATH).concat(PATH);
        }
    }

    public List<StudioGhibliFilmDTO> findAllFilms() throws SipadContenziosoInternalException {
        var response = connector.doGet(BASE_URI, null, null);
        if (!response.getStatusCode().is2xxSuccessful() || !response.hasBody()) {
            throw new SipadContenziosoInternalException(Errore.INTERNAL_REST_ERROR, "FindAll(), microservizio ".concat(BASE_URI), null);
        }
        return (List<StudioGhibliFilmDTO>) response.getBody();
    }

}

额外说明

如果此前功能正常,大概率是之前的代码并未使用静态变量存储配置值,而是用实例变量管理。静态变量在Spring环境中通常不建议用于存储依赖注入的配置,除非有特殊需求——优先使用实例变量配合Spring的生命周期管理,能避免这类初始化时机的问题。

内容的提问来源于stack exchange,提问作者Saverio Mirko Viola

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 13:06:17