You learned how to set up Spring Cloud Config Server, connect it to a config store (like Git), and how client microservices can fetch their settings from a centralized store. That's great, but there's still a problem: how do you update config without restarting the microservice? Alright, time to take this fortress "on the fly"! Today we'll dig into how to dynamically update configs using Spring Cloud Bus and events. Yup — everything will happen in real time.
Problems with updating configurations
Imagine you're the app admin in a distributed microservices architecture. You want to change one tiny setting, for example the external API URL or the logging level. Without dynamic updates you have to:
- First change the settings in the config.
- Then restart all affected microservices.
Sounds like work you want to avoid (hands up if you love downtime!). Especially in production, where those restarts can hurt your users and your teammates.
Solution? Dynamic config updates. Instead of restarting the service we can update configs "on the fly" using tools from the Spring ecosystem.
Approach to dynamic config updates
Why do we need Spring Cloud Bus?
Spring Cloud Bus is a tool that links microservices using a distributed message bus. Put simply: it lets you "tell" other services that something changed. For example, when config is updated Spring Cloud Bus can notify all connected microservices that they should fetch fresh settings from the Spring Cloud Config Server.
How does the process work?
- You update a config file in Git (or another store).
- The Config Server pulls in the changes.
- Spring Cloud Bus uses a message broker (for example, RabbitMQ) to notify all microservices about the change.
- Microservices pull the updated settings locally.
Hands-On: updating configurations on the fly
What we'll use:
- Spring Boot for the microservices.
- Spring Cloud Config for centralized config management.
- Spring Cloud Bus for notifications.
- RabbitMQ as the message broker.
You could use a different broker, like Apache Kafka, but for our example we'll pick RabbitMQ because it's easy to set up and works well with Spring Cloud Bus.
Implementation steps
Step 1: Set up RabbitMQ
First, install RabbitMQ. If you already have it running, skip ahead.
To run it in Docker use:
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management
- RabbitMQ management UI is available at:
http://localhost:15672/ - Login:
guest, password:guest.
Step 2: Configure the Spring Cloud Config Server
We'll use the Config Server we created in previous lectures. Add the following dependency to your Config Server's pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
This dependency wires Spring Cloud Bus to use RabbitMQ.
Now add the following to the Config Server's application.yml:
spring:
cloud:
bus:
enabled: true
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
With this, the Config Server will be connected to RabbitMQ to publish events to the bus.
Step 3: Configure the client microservice
In the client microservice also add the spring-cloud-starter-bus-amqp dependency to pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
And configure the RabbitMQ connection by adding this to the client's application.yml:
spring:
cloud:
config:
uri: http://localhost:8888 # Config Server URL
bus:
enabled: true
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
management:
endpoints:
web:
exposure:
include: refresh, bus-refresh
Note the management.endpoints.web.exposure.include. That line lets us call the /actuator/refresh and /actuator/bus-refresh endpoints.
Step 4: Use the @RefreshScope annotation
Now let's change our service so it dynamically reloads settings. We'll use the @RefreshScope annotation for that.
Example code:
@RestController
@RequestMapping("/api")
public class MyController {
@Value("${custom.message:Default message}") // Bind to configuration
private String message;
@GetMapping("/message")
public String getMessage() {
return message;
}
}
Add the @RefreshScope annotation at the class level:
@RefreshScope
@RestController
@RequestMapping("/api")
public class MyController {
// remaining code unchanged
}
Now, every time the config is updated, the message field will be reloaded automatically.
Step 5: Triggering a config update
When you change the configuration (for example, a file in Git), call this API on the server:
curl -X POST http://localhost:8080/actuator/bus-refresh
Where 8080 is the port of the Config Server.
This will send a notification to all clients connected via Spring Cloud Bus so they refresh their configs.
Testing
Let's test it:
- Make sure all services are running (RabbitMQ, Config Server, the client microservice).
- Edit the config file in the store (for example, in Git) — change the value of the property
custom.message. - Run
curl -X POST http://localhost:8080/actuator/bus-refreshto trigger the updates. - Request
http://localhost:8081/api/message(where8081is the client's port) before and after the update. You should see the new property value.
General notes
- If you forget to add the
@RefreshScopeannotation, changes won't apply "on the fly". This is one of the most common mistakes. - Spring Cloud Bus supports multiple message brokers. RabbitMQ is great for quick starts, but in more complex systems you might use Kafka for higher reliability.
- Make sure you included
bus-refreshinmanagement.endpoints.web.exposure.include, otherwise the refresh API won't be available.
Now your application updates configurations dynamically, and microservice restarts are no longer required.
GO TO FULL VERSION