spring cloud config
Written by Mottola Michele - Italy - Reggio Emilia   
Wednesday, 03 May 2023 15:41
Last Updated on Wednesday, 03 May 2023 16:28
AddThis Social Bookmark Button

target

My main target here is to show how spring cloud config work with a real example

what is spring cloud config

As you know, spring cloud has many projects (modules) and spring cloud config is one of these.
His target is to help the programmer to build a server that work as configuration server and also to let the clients to get the configuration from the server.
No one force you to use spring cloud config to build this kind of stuff, but if you use it, you will save a lot of time, because, as we are going to see, with spring cloud is very simple build what i said.

why should i use a config server

the problem is related expecially with microservices that you build with spring boot.
As you know, when you build a microservice with spring boot, it has its configuration file and often you need to modifity it. But a distribuited application can have a lot of microservices, so it can require a lot of time when you have to configure each microservice.
The solution of this problem is to have a centralized server where there are all the configurations of each microservices. In this way when a microservices starts, it will contact the server to get its configuration file.

what i'm going to build

Now what i'm going to do is to build a microservice that works as a server and another one that work as a client and i'm going to show that when the client starts it get its configuration from the server.
To do that i will buil two microservices with spring boot, run them in a local machine (on different ports) and verify what i said.

project code on GitHub

https://github.com/IntellyGit/springCloudConfig

java, spring boot and cloud versions

in this test i'm going to use java 17 but i compile the source with java 11 throught maven.
Spring boot version used is 2.7.9 and spring cloud version 2021.0.6.
These are set in the maven configuration file.
I don't want to focus on many details but pay attention because spring cloud version depend on spring boot version. And spring boot version depend on jdk version.

configuration

The server setup is very simple. You should do almost nothing, you have just create a spring boot application add the right dependency in the pom.xml (basically org.springframework.cloud:spring-cloud-config-server)

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <spring-cloud.version>2021.0.6</spring-cloud.version>
  </properties>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.9</version>
  </parent>  

  <dependencies> 
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-config-server</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</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>

and make it a server config by adding an annotation (@EnableConfigServer) on the main method.

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

  }
}

Now the server is almost done. You have just configure the position where you save the clients configuration file.
There are many way to do that, but the simplest is to use a repository url.
I have used just a local directory and inside put the client configuration file and versioning it with git.
These are the the detailed steps


cd /mnt/hdb6/temp/conf
git init
add .
git commit -m "micro1.properties"

In this directory there is micro1.properties, the configuration file of the client microservice.
I'm going to talk later about this file.

Now you have to set the properties file of the server and tell it that location.

this is the server configuration file
src/main/resources/application.properties

you just should add this line
spring.cloud.config.server.git.uri = file:///mnt/hdb6/temp/conf

Basically the server configuration is done

client configuration

The client configuration is also pretty simple. It is a spring boot application (microservice).
By adding the right dependency (org.springframework.cloud:spring-cloud-starter-config) you enable it to load the configuration file from the server

 <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <spring-cloud.version>2021.0.6</spring-cloud.version
  </properties>
  
 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.9</version>
  </parent>
  
  <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>>

Now you just tell the client the server location so when it start will go there to read its configuration. To do so you have to add to the client configuration properties these lines

spring.application.name = micro1
spring.config.import = optional:configserver:http://localhost:8080
the first line is important because it set the name of the client microservices. It's important because the name of its configuration file on the server start with it.
So in the dir /mnt/hdb6/temp/conf you have micro1.properties

The second line is to declare the url and port of the configuration server.
Moreover due to the fact that in the same machine i will start the client and the server microservices, i need to use two different port.
By default spring boot starts on 8080 port, so i add this line

server.port = 8082

on the default client configuration (on the client application).
In this way client and server will starts on different ports.

It is important to note, that the client application has its own configuration properties and it will read, another configuration file (on the server).
The server value of the configuation file, will override the configuration of the client.
This is important because the test will be based on this point, but i'm going to talk soon about this.

The client microservices is almost done. There are some more code to add to do our test and i'm goint to explain in the next section

test

Now the keypoint is the test, what and how we want to test.
As i said evary microservice has its own configuration file (application.properties in our application) and what we want is override this configuration with the configuration located in the server machine.
So basically what i want to show is that if the client starts alone, then it read its own configuration file and then, if i start the server and the start the client, the client will read its own configuration from the server and override its default value.

The default client application.properties is this

spring.application.name = micro1
server.port = 8082
spring.config.import = optional:configserver:http://localhost:8080
#default 
property1 = myDefaultValue

and its configuration on the remote server is a /mnt/hdb6/temp/conf/micro1.properties file with just that line

property1 = myServerValue

So what i want to show is that if the client starts alone it read
property1 = myDefaultValue
but when i start the server and then i start the client, i read
property1 = myServerValue

But now the problem is how i can read that property value.
There are many way to do that, but i have choose to simple put in the log that value.
To do what i said i just add, in the microservice client, this code

@SpringBootApplication
public class App {

  static final Logger logger = LoggerFactory.getLogger(App.class);

  
  private static Environment env;    

  @Autowired
  public App(Environment env){
    App.env=env;
  }
  
  
    
  public static void main(final String[] args) {
    SpringApplication.run(App.class, args);

  
    logger.info("property1 " + env.getProperty("property1"));
  }
}

I have used the Environment object to read the value of spring configuration. Its getProperty method read exactly the property you want read.
There isn't nothing hard in this code, but the only thing to note is how i inject Environment object in the main method.
As you can see i have not used

@Autowired
Environment env 

because it not work when you inject an object on a static method.
One way to solve the problem is to use the constructor (as i did)

It's time to start out test.
As i said, if you start only the client, for example with this command

mvn spring-boot:run

you will see, in the terminal, something like this

property1 myDefaultValue

but if you start the server and then the client, you will see

property1 myServerValue

what else

In my simple setup, as you saw, the client read the properties file just on the startup. So if you start the server after the client, then the client wont read the configuration on the server.
This is not good in real application.
But just to let you know, it is possibile to configure the application so you can change the configuration and reload it without restart the application.