How to Refresh Spring Boot Configurations at Runtime Without Restart

This article explains why dynamic configuration refresh is needed in Spring Boot, details the @RefreshScope mechanism, provides step‑by‑step implementation code, and shares production best practices and troubleshooting tips for zero‑downtime config updates.

macrozheng
macrozheng
macrozheng
How to Refresh Spring Boot Configurations at Runtime Without Restart

1. Why dynamic configuration refresh is needed?

In traditional Java applications, changing a configuration file 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 be reassembled like Lego blocks.

2. @RefreshScope core principle

1. Working principle diagram

graph TD
    A[修改配置文件] --> B[发送POST刷新请求]
    B --> C[/actuator/refresh 端点]
    C --> D[RefreshScope 刷新机制]
    D --> E[销毁旧Bean并创建新Bean]
    E --> F[新配置立即生效]

2. Key technical analysis

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 necessary dependencies

<!-- pom.xml -->
<dependencies>
    <!-- Spring Boot core -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Configuration refresh core -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- Config center support -->
    <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!"

## Expose refresh endpoint (critical!)
management:
  endpoints:
    web:
      exposure:
        include: refresh,health,info

Step 4: Create dynamic configuration bean

@Service
@RefreshScope
public class FeatureService {
    // Inject refreshable configuration items
    @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

After modifying application.yml, send a POST request to the refresh endpoint:

curl -X POST http://localhost:8080/actuator/refresh

The response lists the keys that were changed, for example:

["app.feature.timeout", "app.feature.welcome-msg"]

4. Deep dive into @RefreshScope

1. Scope proxy principle

// Pseudo‑code: how Spring implements dynamic refresh
public class RefreshScopeProxy implements ApplicationContextAware {
    private Object targetBean;
    @Override
    public Object invoke(Method method) {
        if (configChanged) {
            // 1. Destroy old bean
            context.destroyBean(targetBean);
            // 2. Recreate bean
            targetBean = context.getBean(beanName);
        }
        return method.invoke(targetBean, args);
    }
}

2. Refresh scope control techniques

Scenario 1 – only properties annotated with @Value are refreshed:

@Component
@RefreshScope
public class PaymentService {
    // Only @Value fields will be refreshed
    @Value("${payment.timeout}")
    private int timeout;
    // Non‑refreshable field
    private final String apiVersion = "v1.0";
}

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: $2a$10$...

2. Automatic refresh solutions

Git webhook auto‑refresh or Nacos config‑center auto‑refresh:

# bootstrap.yml
spring:
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        auto-refresh: true

6. Common troubleshooting

Problem 1: Configuration not effective after refresh

Check that @RefreshScope is added to the bean.

Verify the refresh endpoint returns the modified keys.

Enable debug logging:

logging.level.org.springframework.cloud=DEBUG

Problem 2: Multi‑instance refresh out of sync

# Use Spring Cloud Bus to synchronize refresh
curl -X POST http://host:port/actuator/bus-refresh

Problem 3: Configuration update causing memory leak

@PreDestroy
public void cleanUp() {
    // Clean up resources
}

7. Extended application scenarios

Dynamic feature toggles, runtime log‑level adjustment, and database connection‑pool tuning can also be driven by @RefreshScope:

# Enable new feature instantly
feature.new-checkout.enabled=true

@RefreshScope
public class LogConfig {
    @Value("${logging.level.root}")
    private String logLevel;
}

# Adjust DB pool size dynamically
spring.datasource.hikari.maximum-pool-size=20

Conclusion

Using @RefreshScope provides zero‑downtime configuration updates, immediate effect of application parameters, more flexible operations, and optimal resource utilization. In production, avoid refreshing sensitive data, combine with a configuration center, and protect the refresh endpoint.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Cloud NativeMicroservicesBackend DevelopmentDynamic ConfigurationSpring BootRefreshScope
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.