Spring Cloud: Supplying config data externally using git remote repository.
If you are familiar with SpringBoot then you must be familiar with config properties that we supply to application at runtime. These properties could be database related information or some property which we do not want to hardcode in the application.
The traditional approach has been to write these config properties directly to the code base application.proprties or application.yml file. Things are all right but the problem is the main purpose for which we defined the property file is gone. We wanted the config property to make it a plug and play. But now after each change, build the app and then deploy it. So the core purpose remained unaddressed. The spring cloud came to rescue.
Now the concept is have a configserver which can supply the content to application built by picking it either from some filesystem or from some git remote repository. Now, whenever there is any requirement to change the configuration then just chnage the config file and then either re- deploy the app or trigger a change in the app using spring actuator. *** The concept of retriggering the change will discuss later. First we are going with the concept of chnage the config file and re-deploy.
Let’s illustrate this with the help of an example.
Steps:
- We will create a config server
- Next will create a git repository for the config file
- We will create a springboot Application using the config information.
Creating Config server:
The above is the code for the config server. The points to remember while creating config server are
- Setting up config properties
- Enabling Config Server inside the application. We will have a look here.
Now the config server is ready and would be running on port 8071.
Here is the gradle file used:
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.1'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.spcloud'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "2023.0.0")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-config-server'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
tasks.named('test') {
useJUnitPlatform()
}
Creating a properties repository on github:
Hover inside to look for the config properties.
Creating the sample SpringBoot app consuming the config properties.
This is a springboot application with a sample controller class using the config value supplied via config server.
Setting up config properties to fetch content:
The gradle file for the accounts:
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.1'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.spcloud'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "2023.0.0")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-config'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
tasks.named('test') {
useJUnitPlatform()
}
The above approach is good and working but now here the issue is each time we channge some configuartion we would require to redeploy the app in the server. We overcome the problem of rebuilding the app if the config file is changed but what about the redeployment overhead.
We can overcome this as well using the help of actuator endpoint. The spring actuator had a endpoint refresh which basically updates the config properties at runtime without the need to redeploy the app again. We will do small change in our config file and we would be able to achieve the same.
Refreshing the config properties of the go using spring actuator:
Update your app with the below config.
server.port=8080
spring.application.name=accounts
spring.profiles.active=prod
spring.config.import=optional:configserver:http://localhost:8071/
# Exposing the refresh endpoint to change the config runtime
management.endpoints.web.exposure.include=*
The last line will expose the refresh endpoint for refreshing the config value at runtime. We also need to add a decorater @RefreshScope to the component where we want to show up the refreshed change.
package com.spcloud.accounts.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/accounts")
@RefreshScope
public class AccountController {
@Value("${text.info}")
String sampleText;
@GetMapping("/hi")
public ResponseEntity<String> getHi()
{
String val = "Hello" + sampleText;
return new ResponseEntity<String>(val, HttpStatus.OK);
}
}
Once changes are made. Change the config value in your githb repo. Then, make a post call on the refresh api.
On performing refresh the response output will show all the values refreshed. The first info is system default ignore.