How to Refresh Spring Boot Configurations at Runtime with @RefreshScope
This article explains why dynamic configuration refresh is needed in Spring Boot, details the @RefreshScope mechanism, provides step‑by‑step implementation code, and shares best practices and troubleshooting tips for zero‑downtime updates in production environments.
1. Why dynamic refresh is needed?
Service interruption: Restart makes the service unavailable.
State loss: In‑memory temporary data is cleared.
Complex operations: Requires elaborate deployment procedures.
2. @RefreshScope core principle
2.1 Working principle diagram
graph TD
A[Modify configuration file] --> B[Send POST refresh request]
B --> C[/actuator/refresh endpoint]
C --> D[RefreshScope refresh mechanism]
D --> E[Destroy old Bean and create new Bean]
E --> F[New configuration takes effect immediately]2.2 Key technical analysis
Scope proxy: Creates a dynamic proxy for the Bean to intercept method calls.
Configuration binding: Re‑binds @Value annotated values when configuration changes.
Bean lifecycle management: Destroys and re‑initialises Beans marked with @RefreshScope.
3. Complete implementation steps
Step 1: Add necessary dependencies
<!-- pom.xml -->
<dependencies>
<!-- Spring Boot starter web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Actuator for refresh endpoint -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Spring Cloud starter (for config server / bus) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
<version>3.1.3</version>
</dependency>
</dependencies>Step 2: Enable refresh mechanism
// Main application class
@SpringBootApplication
@EnableRefreshScope // enable configuration refresh capability
public class DynamicConfigApp {
public static void main(String[] args) {
SpringApplication.run(DynamicConfigApp.class, args);
}
}Step 3: Configure application.yml
# Application base configuration
app:
feature:
enabled: true
timeout: 5000
retry-count: 3
welcome-msg: "Hello, Dynamic Config!"
management:
endpoints:
web:
exposure:
include: refresh,health,infoStep 4: Create dynamic configuration Bean
@Service
@RefreshScope // mark this Bean as refreshable
public class FeatureService {
@Value("${app.feature.enabled}")
private boolean featureEnabled;
@Value("${app.feature.timeout}")
private int timeout;
@Value("${app.feature.retry-count}")
private int retryCount;
@Value("${app.feature.welcome-msg}")
private String welcomeMessage;
public String getFeatureConfig() {
return String.format(
"Feature Enabled: %s
Timeout: %d ms
Retry Count: %d
Message: %s",
featureEnabled, timeout, retryCount, welcomeMessage);
}
}Step 5: Create test controller
@RestController
@RequestMapping("/config")
public class ConfigController {
private final FeatureService featureService;
public ConfigController(FeatureService featureService) {
this.featureService = featureService;
}
@GetMapping
public String getConfig() {
return featureService.getFeatureConfig();
}
}Step 6: Trigger configuration refresh
curl -X POST http://localhost:8080/actuator/refreshResponse example (modified keys): ["app.feature.timeout", "app.feature.welcome-msg"]
4. Deep understanding of @RefreshScope
4.1 Scope proxy principle (pseudo‑code)
public class RefreshScopeProxy implements ApplicationContextAware {
private Object targetBean;
@Override
public Object invoke(Method method) {
if (configChanged) {
// destroy old Bean
context.destroyBean(targetBean);
// recreate Bean
targetBean = context.getBean(beanName);
}
return method.invoke(targetBean, args);
}
}4.2 Refresh scope control tricks
Scenario 1 – Refresh specific Bean properties only
@Component
@RefreshScope
public class PaymentService {
@Value("${payment.timeout}")
private int timeout; // will be refreshed
private final String apiVersion = "v1.0"; // will NOT be refreshed
}Scenario 2 – Composite configuration class refresh
@Configuration
@RefreshScope
public class AppConfig {
@Bean
@RefreshScope
public FeatureService featureService() {
return new FeatureService();
}
@Value("${app.theme}")
private String theme;
}5. Production best practices
Secure the refresh endpoint (authentication, custom path).
Use Spring Cloud Bus (POST /actuator/bus-refresh) to synchronize refresh across multiple instances.
Enable auto‑refresh with a configuration center such as Nacos (auto-refresh: true).
6. Common troubleshooting
Issue 1 – Configuration not effective after refresh
Check that the Bean is annotated with @RefreshScope.
Verify the refresh endpoint returns the modified keys.
Enable debug logging: logging.level.org.springframework.cloud=DEBUG.
Issue 2 – Multi‑instance refresh out of sync
Use Spring Cloud Bus to broadcast the refresh:
curl -X POST http://host:port/actuator/bus-refreshIssue 3 – Memory leak after configuration update
@PreDestroy
public void cleanUp() {
// release resources
}Conclusion
Zero‑downtime configuration updates.
Immediate effect of application parameters.
More flexible operational experience.
Maximum resource utilization.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
