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.
|