Problem with Distributed Configuraton Management
In microservice architectures, each service typically maintains its own configuration file. A system composed of dozens or hundreds of services results in scattered configuration files across multiple projects, making maintenance and updates extremely cumbersome.
Just as service registry and discovery centralized service endpoints, a configuration center centralizes configuration files, providing a unified management interface.
Core Capabilities of Spring Cloud Config
Spring Cloud Config addresses the challenges of distributed configuration management with the following features:
- Server and Client Support: Provides both server-side configuration storage and client-side consumption
- Multi-Environment Management: Centralizes configuration across dev, test, and production environments
- Hot Reload: Configuration changes take effect immediately with out service restarts
- Version Control: Leverages Git's version history for configuration changes
- High Concurrency: Supports multiple client requests efficiently
- Language Agnostic: Works with any programming language through REST API
Server Implementation
Repositoyr Structure
Create a Git repository to store configuration files. For demonstration purposes, three files were created representing different environments:
app-config-dev.propertiesapp-config-test.propertiesapp-config-prod.properties
Each file contains a property app.greeting with values corresponding to the environment: "development mode", "test mode", "production mode".
Project Setup
Create a Spring Boot project with the config server dependency:
<?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 http://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.1.6.RELEASE</version>
</parent>
<groupId>com.example</groupId>
<artifactId>config-server</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</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-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>
</project>
Application Configuration
server.port=8888
spring.application.name=config-server
spring.cloud.config.server.git.uri=https://github.com/user/config-repo
spring.cloud.config.server.git.search-paths=configs
spring.cloud.config.server.git.username=your-username
spring.cloud.config.server.git.password=your-password
spring.cloud.config.server.git.default-label=main
Enable Configuration Server
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
Access Endpoints
Configuration files are exposed as REST endpoints following these patterns:
GET /{appName}/{profile}GET /{appName}-{profile}.ymlGET /{label}/{appName}-{profile}.properties
For example, accessing http://localhost:8888/app-config/test retrieves the test environment configuration.
Client Implementation
Project Setup
Create a client application that consumes configuration from the server:
<?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 http://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.1.6.RELEASE</version>
</parent>
<groupId>com.example</groupId>
<artifactId>config-client</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</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>
</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>
</project>
Configuration Files
Create two configuration files in the resources directory.
application.properties:
server.port=9000
bootstrap.properties:
spring.cloud.config.name=app-config
spring.cloud.config.profile=test
spring.cloud.config.uri=http://localhost:8888/
spring.cloud.config.label=main
Configuration Parameters:
| Property | Description |
|---|---|
spring.cloud.config.name |
Application name matching the config file prefix |
spring.cloud.config.profile |
Environment profile (dev, test, prod) |
spring.cloud.config.label |
Git branch name |
spring.cloud.config.uri |
Config server URL |
Cloud configuration properties must reside in bootstrap.properties because these values are loaded before the main application context initializes.
Controller Implementation
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigController {
@Value("${app.greeting}")
private String greetingMessage;
@GetMapping("/greeting")
public String getGreeting() {
return greetingMessage;
}
}
Startup Class
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
}
Local Storage Alternative
For scenarios where Git is not preferred, Spring Cloud Config supports local file storage:
spring.profiles.active=native
spring.cloud.config.server.native.search-locations=file:/app/configs
However, using Git is recommended for better version control and audit capabilities.
API Reference
Common endpoint patterns for accessing configuration:
GET /{application}/{profile}
GET /{application}-{profile}.properties
GET /{application}/{profile}/{label}
GET /{label}/{application}-{profile}.properties