In this tutorial series of spring cloud config, we will be discussing about refreshing property configuration at run-time.We will be doing so using spring boot actuator /refresh
endpoint. Also, we will take a look into refreshing @Value
properties using @RefreshScope
annotation.
In my last tutorial of spring cloud config, we set up a cloud config service with discovery server and discovery client and successfully created an example to read application configuration properties in a distributed environment with GIT backened store.Here, we will continue from there to demo the functionality of refreshing property configuration in spring cloud config at run-time.
In this article we will be only focussing on refreshing config properties. So, we will not be using discovery server related configuration. We will have a config server to load properties from GIT store and config client with actuator project.
Different Ways to Refresh Properties
A simple way to refresh configuration property is to use /refresh
endpoint provided by spring boot actuator.But this is a manual process and need to be triggered for all the instances.Another way is with /bus/refresh
with spring-cloud-bus and in this case all the instances subscribe to an event and whenever this event is triggered, all the config properties will be automatically refreshed via spring cloud bus broadcasting.And the third way to refresh these properties is by hooking up with VCS. In this article we will be dealing with spring boot actuator refresh endpoint.
Spring Cloud Config Server Implementation
We already have the setup ready for this implementation in my previous article. Here let us briefly discuss about it. We have following application.properties defined in config server and spring boot main application.It exposes REST endpoint as http://localhost:8888 for the client to get the configuration properties.
application.propertiesserver.port=8888 spring.cloud.config.server.git.uri=https://github.com/only2dhir/config-repo.gitSpringCloudConfigExampleApplication.java
package com.devglan.springcloudconfigexample; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; @SpringBootApplication @EnableConfigServer public class SpringCloudConfigExampleApplication { public static void main(String[] args) { SpringApplication.run(SpringCloudConfigExampleApplication.class, args); } }
We have our external configuration properties defined at https://github.com/only2dhir/config-repo.git.Here, we have properties defined for active profile local and global properties.
Spring Cloud Config Client Implementation
For client we have following bootstrap.properties
defined.This is the same file we defined in our previous app here
spring.application.name=spring-cloud-config-client spring.profiles.active=local #spring.cloud.config.uri=http://localhost:8888
Refreshing Configuration Properties with /refresh Endpoint
/refresh
endpoint only refreshes those properties annotated with @ConfigurationProperties
means it does not refresh those properties which are initialized during app initialization. For example we have following configuration class defined that reads property having prefix random
package com.devglan.springcloudconfigclient; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix="random") public class PropertyConfiguration { private String property; public String getProperty() { return property; } public void setProperty(String property) { this.property = property; } }
We have following controller class that uses property prefixed with random and also reads property annotated with @Value
@RestController public class DemoController { @Value("${test.property}") private String testProperty; @Value("${test.local.property}") private String localTestProperty; @Autowired private PropertyConfiguration propertyConfiguration; @RequestMapping("/") public String test() { StringBuilder builder = new StringBuilder(); builder.append("global property - ").append(testProperty).append(" || ") .append("local property - ").append(localTestProperty).append(" || ") .append("property configuration value - ").append(propertyConfiguration.getProperty()); return builder.toString(); } }
For endpoint http://localhost:8080/spring-cloud-config-client/ following will be the output.
Now let us change the configuration proprties defined in the spring-cloud-config-client-local.properties
as below.
test.local.property=test local property changed random.property=random property changed
Now we will be calling the http://localhost:8080/spring-cloud-config-client/refresh POST method of actuator to refresh the property. Following will be the response with the updated properties.
Now if we hit http://localhost:8080/spring-cloud-config-client/ we can see that property coming from class annotated with @ConfigurationProperties has been updated but the property annotated with @Value has not been updated because this is initializes during application startup
To update property annotated with @Value, we need to annotate the class with @RefreshScope. Hence, here we will be annotating controller class with @RefreshScope and restart the client app.After restart again we will make change in the properties file and push the changes to git. This time we have appended the properties value with string twice and again we call the refresh endpoint again. Now, if we hit the url http://localhost:8080/spring-cloud-config-client/ we can find that both the configuration properties annotated with @Value and @ConfigurationProperties has been updated.