@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>
问题原因
- @RefreshScope与@ConfigurationProperties绑定逻辑冲突:
@RefreshScope标注在@ConfigurationProperties类上时,仅会触发Bean重建,但不会自动重新绑定最新的配置属性——配置绑定仅在Bean初始化阶段执行一次。 - 本地配置文件未被重新读取:直接修改本地
application.properties后,Spring Boot默认不会主动加载新内容,缺少配置文件热监听机制。 - 版本不兼容:当前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>
验证步骤
- 启动项目,调用
http://localhost:8888/api/message获取初始值; - 修改
application.properties中的demo.message值; - 调用
http://localhost:8888/actuator/refresh触发刷新; - 再次调用
http://localhost:8888/api/message,应返回新属性值,日志中会显示Bean重建后的新值。
内容的提问来源于stack exchange,提问作者S H
相关产品推荐
相关产品推荐

