How to Dynamically Refresh Spring Boot Configurations with @RefreshScope
This article explains why dynamic configuration refresh is needed in Spring Boot, describes the core principles of @RefreshScope, provides step‑by‑step implementation code, and shares best practices and troubleshooting tips for zero‑downtime configuration updates in production environments.
In traditional Java applications, modifying configuration files requires restarting the service, which leads to service interruption, loss of in‑memory state, and complex deployment processes.
Service interruption: The service is unavailable during restart.
State loss: Temporary data in memory is cleared.
Operational complexity: Requires elaborate release procedures.
Spring Boot's @RefreshScope solves these problems by enabling hot configuration updates, allowing applications to reassemble like LEGO blocks without downtime.
1. Why Need Dynamic Refresh?
2. Core Principles of @RefreshScope
1. Working Diagram
graph TD
A[Modify config 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. Key Technical Details
Scope proxy:
Creates a dynamic proxy for the Bean to intercept method calls.
Configuration binding:
Re‑binds values annotated with @Value when configuration changes.
Bean lifecycle management:
Destroys and re‑initializes Beans marked with @RefreshScope.
3. Complete Implementation Steps
Step 1: Add Required Dependencies
<!-- pom.xml -->
<dependencies>
<!-- Spring Boot starter -->
<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 -->
<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
public class DynamicConfigApp {
public static void main(String[] args) {
SpringApplication.run(DynamicConfigApp.class, args);
}
}Step 3: Configure application.yml
# Application base config
app:
feature:
enabled: true
timeout: 5000
retry-count: 3
welcome-msg: "Hello, Dynamic Config!"
# Expose refresh endpoint (critical!)
management:
endpoints:
web:
exposure:
include: refresh,health,infoStep 4: Create a Dynamically Refreshable 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 a 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
After modifying application.yml, send a POST request to the refresh endpoint:
curl -X POST http://localhost:8080/actuator/refreshExample response (list of changed properties):
["app.feature.timeout", "app.feature.welcome-msg"]4. Deep Dive into @RefreshScope
1. Scope Proxy Mechanism (Pseudo‑code)
// Simplified proxy implementation
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);
}
}2. Refresh Scope Control Techniques
Scenario 1: Refresh only specific Bean properties
@Component
@RefreshScope
public class PaymentService {
@Value("${payment.timeout}")
private int timeout; // Refreshable
private final String apiVersion = "v1.0"; // Not refreshable
}Scenario 2: Refresh an entire configuration class
@Configuration
@RefreshScope
public class AppConfig {
@Bean
@RefreshScope
public FeatureService featureService() {
return new FeatureService();
}
@Value("${app.theme}")
private String theme;
}5. Production Best Practices
1. Secure the Refresh Endpoint
management:
endpoint:
refresh:
enabled: true
endpoints:
web:
exposure:
include: refresh
base-path: /internal
path-mapping:
refresh: secure-refresh
spring:
security:
user:
name: admin
password: <redacted>2. Automatic Refresh Solutions
Solution 1: Git webhook triggers refresh.
Solution 2: Config center integration (example with Nacos)
# bootstrap.yml
spring:
cloud:
nacos:
config:
server-addr: localhost:8848
auto-refresh: true6. Common Troubleshooting
Problem 1: Refresh does not take effect
Ensure @RefreshScope is added to the Bean.
Verify the refresh endpoint returns the modified properties.
Check logs with logging.level.org.springframework.cloud=DEBUG.
Problem 2: Multiple instances are out of sync
# Use Spring Cloud Bus for synchronized refresh
curl -X POST http://host:port/actuator/bus-refreshProblem 3: Configuration update causes memory leak
@PreDestroy
public void cleanUp() {
// Release resources
}7. Extended Use Cases
Dynamic feature toggles: enable/disable modules at runtime.
Runtime log level adjustment:
@RefreshScope
public class LogConfig {
@Value("${logging.level.root}")
private String logLevel; // Applied dynamically
}Database connection pool tuning:
# Dynamically adjust pool size
spring.datasource.hikari.maximum-pool-size=20Conclusion: Embrace Dynamic Configuration
By leveraging @RefreshScope, you achieve zero‑downtime configuration updates, instant parameter changes, more flexible operations, and optimal resource utilization. Follow best practices such as protecting sensitive configurations, integrating with a config center, and securing the refresh endpoint for production stability.
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.
Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
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.
