
Spring Cloud Config
Spring Cloud Config is a project that offers support for externalized configuration in a distributed system for both client side and server side. At server side, Spring Cloud Config helps you to implement a Config Server, which is a central service that manages configuration for applications across all environments. At client side, you can use Spring Cloud Config to automatically fetch appropriate properties at the application startup. In this article, we'll show how to use Spring Cloud Config to implement a Config Server and how to use it at a client side.
Dominik Adamek |
09 May 2022
## Config Server
To implement a Config Server, we'll use:
- Maven
- Spring Boot `2.5.5`
- Spring Cloud `2020.0.4`
In order to start using Spring Cloud Config you will need following Maven dependencies:
```xml
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-config-server
```
Now you can create a Config Server by embedding it into Spring Boot application using `@EnableConfigServer` annotation:
```java
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
In order to serve configuration data, Spring Cloud Config uses the `EnvironmentRepository` interface, which
returns the `Environment` object containing `propertySources`. `EnvironmentRepository` serves property sources
from `/{application}/{profile}/{label}`, where each variable has it's corresponding client side mapping:
- `application` is a `spring.application.name` on the client side
- `profile` is a `spring.profiles.active` on the client side
- `label` can be used for versioned configuration files
Spring Cloud Config allows you to choose between different backend options (different `EnvironmentRepository` implementations) for storing your configuration:
- Git, which is a default backend
- SVN
- File System
- Vault
- JDBC (relational database storage)
- Redis
- AWS S3
- CredHub
Additionally, you may want to fetch configuration from multiple sources. In order to do that, you need to set `spring.profiles.active=composite`
in your Config Server's `application.properties` (or YAML). Then you can configure different types of configuration backends.
For the purpose of this article, we will use a File System Backend as this is a perfect candidate for getting started quickly
with Spring Cloud Config. However, you should be careful using this backend on production and consider to use other types.
File System Backend comes along with Config Server's `native` profile. Let's start from activating a `native` profile
in our `application.properties`:
```properties
spring.profiles.active=native
```
With File System Backend, you can load configuration data from the local classpath or file system.
You can use `spring.cloud.config.server.native.searchLocations` to specify the location of your config files.
In our example, we won't specify this property and expect Config Server to load data from the classpath as this is the default behaviour.
Let's create two configuration files for our Client app with two separate profiles `dev` and `prod` under `src/main/resources`:
- client-dev.properties:
```properties
my.custom.property=dev
```
- client-prod.properties:
```properties
my.custom.property=prod
```
Now, let's run our Config Server and verify it by calling: `http://localhost:8080/client/dev`. You should expect a following response:
```json
{"name":"client","profiles":["dev"],"label":null,"version":null,"state":null,"propertySources":[{"name":"class path resource [client-dev.properties]","source":{"my.custom.property":"dev"}}]}
```
## Encryption and Decryption
If your configuration files contain secret values like passwords, you can use the encryption and decryption features
of Spring Cloud Config. Please note that those features require JCE (Java Cryptography Extension) to be installed in your JVM.
Once that is in place, you may use built-in `/encrypt` and `/decrypt` endpoints to use Spring Cloud Config security features.
Assuming your instance of the Config Server is running on `localhost:8080`, you can follow this example to encrypt your secret:
```shell
$ curl localhost:8888/encrypt -d myPassword
```
Then you can use the response from `/encrypt` in the configuration file starting with `{cipher}`:
```properties
my.custom.username=dev-user
my.custom.password='{cipher}'
```
All encrypted values (starting with `{cipher}`) are decrypted before sending to clients.
## Client Side Setup
For the client side implementation, we'll use the same base stack as for the Config Server, including Maven, Spring Boot and Spring Cloud.
Additionally, we will use `spring-boot-starter-actuator` to demonstrate the `Environment` content at the client side.
To start using Spring Cloud Config in the client application, you will need following Maven dependencies:
```xml
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-config
```
For testing purposes, let's use a non-standard 8081 port and create `application.properties` files under `/src/main/resources/`:
```properties
server.port=8081
spring.application.name=client
spring.config.import=optional:configserver:http://localhost:8080
management.endpoints.web.exposure.include=*
```
Spring Cloud Config requires `spring.config.import` property to be set, so then it can use it to fetch configuration data from the Config Server
at the application startup. We are also setting `spring.application.name` property, which will be used at the Config Server side,
to lookup appropriate properties. The second required property for server-side property lookup is the `profile` which we will pass along with the run command
(or you can specify it in your IDE's run configuration). Let's create a very basic main class:
```java
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
Now we can start the application in a `dev` profile (please make sure before that your Config Server is up and running):
```shell
mvn spring-boot:run -Dspring-boot.run.profiles=dev
```
You may notice following lines in the startup log:
```shell
Fetching config from server at : http://localhost:8080
Located environment: name=client, profiles=[dev], label=null, version=null, state=null
```
In order to verify the value of our `my.custom.property`, let's use the built-in `env` endpoint of Spring Actuator:
```shell
curl http://localhost:8081/actuator/env/my.custom.property
{"property":{"source":"configserver:class path resource [client-dev.properties]","value":"dev"},"activeProfiles":["dev"],"propertySources":[{"name":"server.ports"},{"name":"commandLineArgs"},{"name":"servletConfigInitParams"},{"name":"servletContextInitParams"},{"name":"systemProperties"},{"name":"systemEnvironment"},{"name":"random"},{"name":"cachedrandom"},{"name":"springCloudClientHostInfo"},{"name":"configserver:class path resource [client-dev.properties]","property":{"value":"dev","origin":"Config Server class path resource [client-dev.properties]:1:20"}},{"name":"configClient"},{"name":"Config resource 'class path resource [application.properties]' via location 'optional:classpath:/'"},{"name":"Management Server"}]}
```
You can verify the value for the `prod` profile as well and try to experiment with an additional labels at Config Server side,
so you can see how you can version your config data.
## Summary
In this article, we explored the basic concepts and features of Spring Cloud Config based on two Spring Boot Microservices working as a client and a server.
To demonstrate how it works, we created a Config Server with a File System backend, and the client application fetching data from it.
However, Spring Cloud Config offers you many options to choose a backend for your configuration data, so feel free to try it out in your project.
Dominik Adamek
Senior Software Developer with 7 years of experience in Java and Spring. Big fan of Microservices, Docker and Clean Architecture.
Did you like this article?
2,0 / 2