Microservices Configuration Management with Spring Boot


In this article, we’re going to look at Configuration Management in Microservices with Spring Boot + Spring Cloud Config Server.  While working on microservices we have the challenge to manage configuration for multiple microservices which have multiple instances.

To solve this problem, we are going to use the Spring Cloud Config which is a project under the Spring Cloud umbrella. Spring Cloud Config provides an approach to store all configuration of microservices in a git repository.

Spring Cloud Config provides server-side and client-side support for externalized configuration in a distributed system. With the Config Server, you have a central place to manage external properties for applications across all environments.

1. What we’ll build

In this tutorial, we will create a config server which will provide configuration for other microservices from a git repository. We will store our application.properties file on a git repository and create two Spring Boot application:

  1. config-server
  2. student-service

After that, we will change the application.properties values on the fly and application will read it without restarting.

Microservices Configuration Management with Spring Boot

2. What we’ll need

  • About 30 minute
  • JDK 1.8 or later
  • Spring Boot 2.2.6.RELEASE
  • Spring Cloud Server & Config
  • Gradle 4+ or Maven 3.2+
  • Your favourite IDE:
    • Spring Tool Suite (STS)
    • Eclipse
    • IntelliJ IDEA

3. Student Service

Create a student-service project and follow the below steps:

3.1 Dependencies Required

Add the below dependencies to your pom.xml file of the student-service project.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.6.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>org.websparrow</groupId>
	<artifactId>student-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>student-service</name>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

3.2 Project Structure

The final project structure of the student-service application in STS 4 IDE will look like as follows:

Microservices Project Structure of Client Config

3.3 bootstrap.propertise

bootstrap.properties will set basic properties for application and other needful values used in the application will be provided by the Config Server.

bootstrap.propertise
# Name of the application
spring.application.name=student-service

# Config server URL
spring.cloud.config.uri=http://localhost:8000

# Profile name if any
# Check more about Profile
# https://websparrow.org/spring/spring-boot-profiles-and-configuration-management-example
spring.profiles.active=dev

#Spring Boot Actuator
management.endpoints.web.exposure.include=refresh

spring.cloud.config.uri= http://localhost:8000  → URL of the Config Server

spring.profiles.active= dev →  Application can run on multiple environments so here we are set the active profile to dev. Check out more about Spring Boot Profile.

management.endpoints.web.exposure.include= refresh → exposing only to refresh endpoint of the actuator. So, we can use this endpoint to refresh the configuration on-demand, without restarting the JVM.

3.4 DTO

Student.java
package org.websparrow.model;

public class Student {

	private Integer records;

	public Integer getRecords() {
		return records;
	}

	public Student(Integer records) {
		super();
		this.records = records;
	}

	public Student() {
		super();
	}
}

3.5 Configuration

Adds the field having prefix student in the properties file (for me its student-service-dev.properties in a separate repository) and creates a bean for StudentConfig class.

StudentConfig.java
package org.websparrow.configuration;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "student")
public class StudentConfig {

	private Integer records;

	public Integer getRecords() {
		return records;
	}

	public void setRecords(Integer records) {
		this.records = records;
	}
}

3.6 Controller

StudentController.java
package org.websparrow.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.websparrow.configuration.StudentConfig;
import org.websparrow.model.Student;

@RestController
public class StudentController {

	@Autowired
	private StudentConfig studentConfig;

	@GetMapping("/student")
	public Student getStudent() {
		return new Student(studentConfig.getRecords());
	}
}

3.7 Spring Boot Starter

StudentServiceApplication.java
package org.websparrow;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = "org.websparrow.*")
public class StudentServiceApplication {

	public static void main(String[] args) {
		SpringApplication.run(StudentServiceApplication.class, args);
	}
}

4. Git Repository for Properties Files

In this step, we will create 3 property file for our student-service microservice in a separate repository.

Link: https://github.com/luciferMF/config-server-properties

student-service.properties
student.records=100
management.security.enabled=false

management.security.enabled= false  → will disable security for accessing actuator endpoint. This property will be picked form student-service.properties file and others will be used from student-service-dev.properties file.

student-service-dev.properties
student.records=199
student-service-qa.properties
student.records=5

As we already set dev as the active profile for our student-service, student-service-dev.properties will be used.

Make sure application properties file name should start with the name you set in your application with spring.application.name refer to Step 3.3.

5. Config Server (Spring Cloud Config Server)

Set up a Config Server and build a client that consumes the configuration on startup and then refreshes the configuration without restarting the client.

5.1 Dependency Required

The required dependencies to set up Spring Cloud Config Server are the followings. Add them to pom.xml file of the config-server application.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.6.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>org.websparrow</groupId>
	<artifactId>config-server</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>config-server</name>
	<description>config server</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-config-server</artifactId>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

3.2 Project Structure

The final project structure of the config-server application in STS 4 IDE will look like as follows:

Microservices Project Structure of Config Server

5.3 application.properties

spring.cloud.config.server.git.uri is used to set a repository URL. If you are using local directory as repository add file:// as the prefix to the path.

application.properties
server.port=8000
spring.application.name=config-server
spring.cloud.config.server.git.uri=https://github.com/luciferMF/config-server-properties

5.4 Spring Boot Starter

Just annotate ConfigServerApplication class with @EnableConfigServer annotation and job is done. 🙂

ConfigServerApplication.java
package org.websparrow;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(ConfigServerApplication.class, args);
	}
}

6. Testing

Follow the these below steps to test the application accurately.

1. Start your both application one by one. Make sure you start config-server first.

2. After the successful startup of both applications hit http://localhost:8080/student in Postman client/web browser. Response is:

{
    "records": 999
}

3. Now update the student-service-dev.properties file and commit your file and push it to the repository.

student.records=100

Repository URL: https://github.com/luciferMF/config-server-properties

4. Before hitting the student-service (http://localhost:8080/student) again we must refresh it. Hit below URL with the Postman. It will refresh your properties in the application.

URL: http://localhost:8080/actuator/refresh

Method: POST

[
    "student.records",
    "config.client.version"
]

5. Again hit http://localhost:8080/student, you will get the updated response without restarting student-service.

{
    "records": 100
}

Alternatively, you can check out the project from below GitHub repositories:

References

  1. Spring Cloud Config
  2. Centralized Configuration
  3. Spring Boot Profiles and Configuration Management Example
  4. Spring Boot Actuator: Overview and Getting Started

Similar Posts

About the Author

Manish Fartiyal
Hi!, I'm Manish Fartiyal, a full-stack web application developer. I love Java and other open-source technology, currently working at one of the top MNC in India. Read all published posts by Manish Fartiyal.