To demonstrate the Spring Cloud Config concept we need 3 applications:
- Git Repository.
- Spring Cloud Config Server.
- Spring Cloud Config Client (the microservice application).
In the below diagram the interest-rates-service is a microservice where we had added the Spring Cloud Config Client dependency. Also there would be other microservices in the vicinity who may be using the same config server :
1. Git Repository:
We will name this application as – interest-rates-repo
(You can use local git repo as well, but in real life environment you will be using a remote git repo).
In the repo you can add below files:
interest-rates.properties
interest-rates-dev.properties
interest-rates-uat.properties
The above 3 files would be for production, development, and UAT respectively.
You can find the GitHub URL for the same here : https://github.com/heapsteep/interest-rates-repo.git
2. Spring Cloud Config Server:
Now we will create a spring boot project from Spring Initializr. We will give it this name- config-server . Add the below dependency and create the config server application:
One can see the below dependency in the pom.xml:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
Add below items in application.properties:
server.port=8888 spring.cloud.config.server.git.uri=https://github.com/heapsteep/interest-rates-repo.git spring.cloud.config.server.git.default-label=master
The last line in the above properties file specifies the branch of the code you are considering. If you don’t specify that, you will get below exception:
org.springframework.cloud.config.server.environment.NoSuchLabelException: No such label: main . . . Caused by: org.eclipse.jgit.api.errors.RefNotFoundException: Ref main cannot be resolved
In the main class add below line:
@EnableConfigServer
Start the server. You can test the properties by calling below URL:
http://localhost:8888/interest-rates-dev.properties
http://localhost:8888/interest-rates.properties
If you change any of the value in the repo, the value in the config-server will be updated automatically, without any restart of the Config Server.
GitHub location for the above Config Server application is here: https://github.com/heapsteep/config-server.git
3. Spring Cloud Config Client:
Now lets create the Config Client, we will give it the name- interest-rates-service. In real life this would be the microservice application.
Create an spring boot application by importing below dependency:
One can see the below dependency in the pom.xml:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
Create the bean class:
@Data @AllArgsConstructor public class InterestRates { int home; int motor; }
And the controller:
@RestController @RefreshScope public class TestController { @Value("${interest.home}") private String home; @Value("${interest.motor}") private String motor; @GetMapping("/getRates") @ResponseBody public InterestRates getRates() { return new InterestRates(Integer.parseInt(home),Integer.parseInt(motor)); } @GetMapping("/getRate_home") @ResponseBody public String getRate_home() { try { return this.home.toString(); } catch (Exception e) { e.printStackTrace(); return "Error: " + e.getMessage(); } } }
In application.properties:
spring.application.name=interest-rates server.port=8080 spring.config.import=optional:configserver:http://localhost:8888 spring.profiles.active=dev management.endpoints.web.exposure.include=*
Just make sure that the value of spring.application.name should match with the the name of .properties file in the repo, i.e., interest-rates.properties file here.
In the above properties file we have set the profile to dev. If you want to make it to prod, just keep it blank.
http://localhost:8080/getRates
GitHub URL of the same Config Client can be found here: https://github.com/heapsteep/interest-rates-service.git
But still there is a problem- If you change some values in the repo, although it will automatically get updated in the config-server application, but it will not get updated automatically in the config-client application. You need to restart the config-client. To avoid the restart, you have to add below 3 changes in the code and do some other activities as mentioned below:
1.In the RestController class add this line: @RefreshScope.
2.Add the actuator dependency to config-client application.
3.Add the below line in bootstrap.properties. This will enable all actuator urls.
management.endpoints.web.exposure.include=*
Now from a REST client like Postman do a POST call (no body) to the below URL:
For Spring Boot 1.x+ call this URL: http://localhost:8080/refresh
For Spring Boot 2.0.0+ call this URL: http://localhost:8080/actuator/refresh
Finally, you will see the updated changes in config-client application.
But in real world, there would be lot of microservices. You can’t give a refresh call to each and every microservices running on different port. For that you have to take help of – Spring Cloud Bus.
But, with Spring Cloud Bus you can refresh all instances of a single microservice, but not for all microservice.