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

@RefreshScope Bean已重建但application.properties属性未刷新问题

Spring Cloud @RefreshScope 不更新application.properties属性的解决方法

问题场景

我有一个Spring Cloud项目,希望在运行时更新application.properties中的属性,让依赖该配置的Bean及配置Bean本身使用新值重建。调用http://localhost:8888/actuator/refresh时Bean会销毁,但属性值并未更新。

操作流程:

  • 调用http://localhost:8888/api/message验证当前属性值;
  • 修改application.properties文件;
  • 调用http://localhost:8888/actuator/refresh接口;
  • 再次调用/api/message,返回的仍是旧值,且@PreDestroy日志中也显示旧值。

尝试过@Value注解,同样无法解决问题。相关代码如下:

ConfigProperties.java

package org.example.refreshscopeworkingproject;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "demo")
@RefreshScope
public class ConfigProperties {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
    @PostConstruct
    public void init() {
        System.out.println("ConfigProperties bean created with message: " + message);
    }
    @PreDestroy
    public void destroy() {
        System.out.println("ConfigProperties destroyed");
    }
}

DemoController.java

package org.example.refreshscopeworkingproject;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
@RefreshScope
public class DemoController {
    private final ConfigProperties configProperties;

    public DemoController(ConfigProperties configProperties) {
        this.configProperties = configProperties;
    }

    @GetMapping("/message")
    public String getMessage() {
        return configProperties.getMessage();
    }


    @PostConstruct
    public void init() {
        System.out.println("Controller initialized");
    }
    @PreDestroy
    public void destroy() {
        System.out.println("Controller destroyed");
    }
}

RefreshScopeWorkingProjectApplication.java

package org.example.refreshscopeworkingproject;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class RefreshScopeWorkingProjectApplication {

    public static void main(String[] args) {
        SpringApplication.run(RefreshScopeWorkingProjectApplication.class, args);
    }

}

application.properties

demo.message=Hello, RefreshScope1111!
management.endpoints.web.exposure.include=*
logging.level.org.springframework.boot.actuate=DEBUG
logging.level.org.springframework.boot.context.properties=DEBUG
server.port=8888

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>RefreshScopeWorkingProject</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>RefreshScopeWorkingProject</name>
    <description>RefreshScopeWorkingProject</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-context</artifactId>
            <version>4.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.6.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

问题原因

  1. @RefreshScope与@ConfigurationProperties绑定逻辑冲突:@RefreshScope标注在@ConfigurationProperties类上时,仅会触发Bean重建,但不会自动重新绑定最新的配置属性——配置绑定仅在Bean初始化阶段执行一次。
  2. 本地配置文件未被重新读取:直接修改本地application.properties后,Spring Boot默认不会主动加载新内容,缺少配置文件热监听机制。
  3. 版本不兼容:当前Spring Boot 3.3.4与Spring Cloud Context 4.0.3版本不匹配(Spring Cloud 4.0.x对应Spring Boot 3.0-3.1.x),可能导致刷新逻辑异常。

解决方案

方案1:修复@ConfigurationProperties与@RefreshScope的配合(推荐)

移除ConfigProperties上的@Component,改用@EnableConfigurationProperties显式启用配置绑定,确保刷新时触发属性重新加载。

修改ConfigProperties.java

package org.example.refreshscopeworkingproject;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;

@ConfigurationProperties(prefix = "demo")
@RefreshScope
public class ConfigProperties {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @PostConstruct
    public void init() {
        System.out.println("ConfigProperties bean created with message: " + message);
    }

    @PreDestroy
    public void destroy() {
        System.out.println("ConfigProperties destroyed with message: " + message);
    }
}

修改启动类RefreshScopeWorkingProjectApplication.java

添加@EnableConfigurationProperties注解:

package org.example.refreshscopeworkingproject;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@EnableConfigurationProperties(ConfigProperties.class)
public class RefreshScopeWorkingProjectApplication {

    public static void main(String[] args) {
        SpringApplication.run(RefreshScopeWorkingProjectApplication.class, args);
    }

}

方案2:使用@Value配合@RefreshScope(简单属性场景)

若使用@Value,需确保依赖属性的Bean被@RefreshScope标注,且每次访问属性时直接从Spring环境获取最新值:

修改DemoController.java

package org.example.refreshscopeworkingproject;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
@RefreshScope
public class DemoController {

    @Value("${demo.message}")
    private String message;

    @GetMapping("/message")
    public String getMessage() {
        return message;
    }

    @PostConstruct
    public void init() {
        System.out.println("Controller initialized with message: " + message);
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Controller destroyed with message: " + message);
    }
}

补充:本地开发启用配置文件热监听

添加spring-boot-devtools依赖,实现本地配置文件修改后的自动感知:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>

版本兼容修复

将Spring Cloud Context版本升级到与Spring Boot 3.3.4匹配的2023.0.3(Leyton SR3):

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-context</artifactId>
    <version>2023.0.3</version>
</dependency>

验证步骤

  1. 启动项目,调用http://localhost:8888/api/message获取初始值;
  2. 修改application.properties中的demo.message值;
  3. 调用http://localhost:8888/actuator/refresh触发刷新;
  4. 再次调用http://localhost:8888/api/message,应返回新属性值,日志中会显示Bean重建后的新值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 23:52:12