Refreshing Configuration at Runtime
Refreshing Configuration at Runtime
The previous lesson showed how a Config Server centralises your properties so every service reads from one place. But what happens when a value changes — a feature flag, a rate limit, a downstream URL? Without runtime refresh, every change is a redeployment: rebuild, retag, redeploy, restart. In a system with twenty services that is painful; in a system with two hundred it is operationally impossible.
Spring Cloud Config gives you two complementary mechanisms for runtime refresh: the /actuator/refresh endpoint (per-instance, HTTP POST) and Spring Cloud Bus (broadcast to every instance at once via a message broker). This lesson covers both, the security implications of each, and the distributed-systems trade-offs you should understand before picking one.
How Spring Beans Hold Configuration
Before refreshing anything, you need to understand the problem. Spring creates beans eagerly at startup and injects property values at that moment. A plain @Value("${order.timeout}") field is set once — it never changes, no matter what the Config Server returns later.
Spring Cloud solves this with the @RefreshScope annotation. Beans annotated with @RefreshScope are proxy-wrapped. When a refresh event fires, the proxy destroys the underlying bean instance and recreates it from the current environment, picking up fresh property values.
Step 1 — Enable the Actuator Refresh Endpoint
Add the Actuator and Spring Cloud Config Client starters to your service (you should already have the Config Client from the previous lesson):
Then expose the endpoint in application.yml:
include: "*" exposes /actuator/shutdown, /actuator/env, and other sensitive endpoints. In production, expose only what you need and protect every actuator endpoint with Spring Security or a network policy. A misconfigured actuator is one of the most common microservice security holes found in penetration tests.
Step 2 — Annotate the Bean that Holds the Property
Any class that injects OrderProperties will automatically see the updated values after the next refresh, because the proxy transparently delegates to the freshly created instance.
Step 3 — Trigger a Refresh
After updating the value in your Git-backed config repository and committing it, POST to the refresh endpoint of the running service:
The endpoint returns a JSON array of the property keys that changed:
If nothing changed, it returns an empty array. The service is now running with the new values — no restart needed.
Securing the Refresh Endpoint
In production you must protect /actuator/refresh. A POST to it forces a re-read from the Config Server; an attacker who can reach it could inject arbitrary config values if your Config Server is also compromised, or simply force repeated refreshes as a denial-of-service. Add Spring Security and require at least a shared secret:
Scaling the Problem: Spring Cloud Bus
The /actuator/refresh approach works fine with one or two instances. With ten instances of order-service running, you would need to POST to all ten endpoints individually. That is operationally fragile and easy to forget.
Spring Cloud Bus solves this by connecting all instances to a shared message broker (RabbitMQ or Kafka). You POST a single endpoint — on any one instance, or on the Config Server itself — and the Bus broadcasts a refresh event to every subscriber.
Add the Bus dependency (RabbitMQ variant shown here):
Configure RabbitMQ in application.yml:
Expose the bus-refresh endpoint on the Config Server:
After pushing a config change to Git, trigger a fleet-wide refresh with a single call to the Config Server:
/actuator/busrefresh/{destination} accepts a Spring Application Context ID pattern (e.g. order-service:**) so you can target only one service family without restarting every service on the bus. This reduces unnecessary churn in large fleets.
Git Webhooks: Fully Automated Refresh
In a mature setup you remove the manual trigger altogether. Configure your Git host (GitHub, GitLab, Bitbucket) to POST to the Config Server's /monitor endpoint whenever a push happens. Add the Spring Cloud Config Monitor dependency to the Config Server:
Now the full flow is: git push → webhook fires → Config Server parses the changed files → Bus broadcasts refresh → all affected service instances reload their beans. Configuration propagates to every running instance within seconds of a Git commit, with no deployment and no manual curl commands.
Distributed-Systems Trade-offs
Runtime refresh is powerful, but it is not free:
- Partial refresh windows: in the seconds between the first and last instance refreshing, different instances run different configuration. Design your services so they tolerate brief inconsistency, or use feature flags that are safe to be stale.
- Not all beans are refresh-scoped:
DataSource, security filter chains, and other infrastructure beans created by auto-configuration are not annotated with@RefreshScope. Changing a database URL at runtime will not reconnect the pool — a restart is still required for those properties. - Message broker is now critical infrastructure: if you adopt Spring Cloud Bus, the broker becomes a single point of failure for configuration delivery. Use a clustered broker in production, and plan for what happens to services if the broker is temporarily unavailable.
- Audit and rollback: because your config lives in Git, every change is versioned and auditable. To roll back a configuration change you revert the Git commit and trigger another refresh — no service restart needed.
@RefreshScope for business-logic configuration (timeouts, limits, flags, URLs of external partners). Do not use it for structural infrastructure config (port numbers, datasource credentials, security keys). The former is safe to change at runtime; the latter requires a controlled restart.
Summary
@RefreshScope makes any Spring bean live-reloadable without a restart. The /actuator/refresh endpoint triggers a single-instance reload; Spring Cloud Bus broadcasts that trigger to every instance at once. Secure the refresh endpoints with Spring Security, keep infrastructure beans outside refresh scope, and use Git webhooks to automate propagation. In the next lesson you will learn the API Gateway pattern — the front door through which all these services are exposed to clients.