Use Spring Cloud Config to centralize your Spring applications - Ideas2IT

Use Spring Cloud Config to centralize your Spring applications

Share This

Introduction

Spring Cloud Config is a feature provided by the Spring framework to maintain all the configurations of your Spring applications in a central place. It provides client and server-side support for an externalized configuration.

We can store the configuration in Git version control or in the file system as well. Here we are going to see two spring boot applications: one will act as a spring cloud config server and the other will be the client application.

Architecture

Spring cloud config Architecture

Required Dependencies

The server project is relying on “spring-cloud-config-server” dependency,

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

The client application is relying on “spring-cloud-config-client” dependency,

 <dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-config-client</artifactId>
		<version>2.2.1.RELEASE</version>
		<scope>runtime</scope>
</dependency>

Note: You can also use spring-cloud-starter-config dependency instead of spring-cloud-config-client.

Spring Cloud Config Server Implementation

To make the spring application into Cloud Config Server first we need to mention the @EnableConfigServer annotation.

@EnableConfigServer
@SpringBootApplication
public class SpringConfigServerApplication {
		
	public static void main(String[] args) {
		SpringApplication.run(SpringConfigServerApplication.class, args);
	}
}

Next, we need to add the below properties in the application.yml file

Storing Configuration in the Local File System

spring:
	  application:
                  name: config-server
            profiles:
         	      active: native
	 cloud:
	     config:
	        server:
		native:
                           search-locations: file:///C:/Documents/config

The native property tells the server to search for the configuration in the local file system instead of Git. And search-locations is the path of the local file system where you are storing the configuration file.

Storing Configuration in Git

spring:
	  application:
        	      name: config-server
	  cloud:
	    config:
	      server:
	          git:
	            uri: <git url>

Storing configuration in Multiple Locations

spring:
	  application:
        	      name: config-server
              profiles:
                 active: native, git
	  cloud:
	     config:
	         server:
		 native:
	                 search-locations: file:///C:/Documents/config,  file:///C:/Documents/config
		 git:
		     uri: <git url>
		    repos:
		       testapp:
          pattern: test-app
 uri: <git url>	

You can mention multiple search locations for the file system separated by a comma and for multiple Git locations use repos and pattern tags to differentiate the URL so in the above example if the URL has a pattern “test-app” like “localhost:8080/test-app/development”  the config server fetch the value from the URI mentioned for test-app else by default it will fetch from “git.uri” location.

In this demo, I will go with storing the configuration in the local file system. Once done with adding the properties in the applcaiton.yml file then create the configuration file in the path mentioned for “search-locations”. 

Starting Config Server

Step 1 : I have created a file named “redis-client-development.yml”  in C:Documentsconfig. The naming convention of the file name should be the first part that is “redis-client” should match the client application name, and the last part that is “development” shows the profiling for the client application. You can have different files with different profiling like production, and QA.

Example file names for different profiles – redis-client-production.yml,redis-client-qa.yml

The file contains the configuration below which I want to be externalized.

spring:
	  datasource:
	     driver-class-name: com.mysql.jdbc.Driver
	     url: jdbc:mysql://localhost:3306/test
	     username: test
	     password: test

Step 2: Start the application

Once you started the application successfully you hit the endpoint

“http://localhost:9898/redis-client/development” then the response will be:

 {
	   "name":"redis-client",
	   "profiles":[
		  "development"
	   ],
	   "label":null,
	   "version":null,
	   "state":null,
	   "propertySources":[
		  {
			 "name":"file:///C:/Documents/config/redis-client-development.yml",
			 "source":{
				"spring.datasource.driver-class-name":"com.mysql.jdbc.Driver",
				"spring.datasource.url":"jdbc:mysql://localhost:3306/test",
				"spring.datasource.username":"test",
				"spring.datasource.password":"test"
			 }
		  }
	   ]
	}

The development in the URL will be considered as profiling so we have to mention it after “/”.

Spring Cloud Config Client Implementation

The client application is going to be a simple one. We need to add the required dependency for the config client (Please refer to the Required Dependencies section). 

Then we have to add the below properties in our bootstrap.yml file.

 spring:
  application:
    name: redis-client
  profiles:
    active: development
  cloud:
    config:
      uri: http://localhost:9898

Here cloud.config.uri is the URL of the config server. So the Spring boot will understand that it has to fetch for configurations from that URL.

To show that the client application fetches the values from the config server I have created a java file in the client application that populates all its required configurations from the config server.

package com.project.redisdemo.configuration;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {

    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;
    @Value("${spring.datasource.url}")
    private String url;
    @Value("${spring.datasource.username}")
    private String username;
    @Value("${spring.datasource.password}")
    private String password;


    @Bean
    public DataSource getDataSource() {
        DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
        System.out.println("********************************driverClassName - "+driverClassName);
        dataSourceBuilder.driverClassName(driverClassName);
        dataSourceBuilder.url(url);
        dataSourceBuilder.username(username);
        dataSourceBuilder.password(password);
        return dataSourceBuilder.build();
    }
}

This class has @configuration annotation so that the file will get loaded at server startup and also I have added a print statement to show that the values have been fetched from the config server. Now we can start the client application.

Client Application Logs

2021-08-29 20:16:57.850  INFO 10268 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-08-29 20:16:57.850  INFO 10268 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2789 ms
********************************driverClassName - com.mysql.jdbc.Driver
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
2021-08-29 20:16:58.112  INFO 10268 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-08-29 20:16:58.119  WARN 10268 --- [           main] com.zaxxer.hikari.util.DriverDataSource  : Registered driver with driverClassName=com.mysql.jdbc.Driver was not found, trying direct instantiation.
2021-08-29 20:16:58.634  INFO 10268 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.

In the above logs, you can see the MySQL driver class name has been fetched from the config server.

Conclusion 

Now, we are able to create a config server that fetches the config properties from our local file system. And also now we can build the centralized configuration for microservices.

– – – – – –