Spring Cloud: Spring cloud libraries are intended to be used by spring boot applications. They are not intended to be utilized using just the spring framework although it is possible. All of the dependency management is based on spring boot. Most importantly the startup process of the application is usually altered slightly, and the application context is not created in the same straight forward way as a normal spring framework-based application. I am not going to the details here about the spring framework, but I am completely focusing on the spring cloud configuration and service discovery.
Spring Cloud Dependencies Walk Through:
Spring Cloud is a sub-project within the Spring IO Umbrella, and it is itself is an Umbrella project. The point of Spring cloud is to address common patterns in distributed computing which are commonly encountered in cloud environments when using Microservice architectures.
Spring cloud makes it easy to use the main Netflix libraries. Now, the common dependency that you will see in the spring cloud projects is the parent pom:
Look at this POM file in the above image, this, in turn, references the spring boot parent pom. The parent is specified here in this pom file. If you take a regular spring boot project, you have to add the dependency as “spring-boot-starter-parent”. So here I just replaced the word cloud with boot and then it will become the spring boot parent pom. Next in the dependency section here, you have to add the relevant dependency for what you are trying to bring in. The group id will be always “org.springframework.cloud”.
Many projects already specified apparent for their own needs usually an organization standard. We can add always the maven’s dependency management section. It will allow us to reference the parent pom without actually making it the parent. You can think of this as multiple inheritances. The pom will look like as below:
This module is about centralized versioned configuration management for distributed cloud-based application. Now, I am going to explain what Spring Cloud Config is and how we can build and run our own spring cloud config server is. Also, I am going to explain how you can establish your own repository for holding configuration information.
As you know that Applications have connections to resources like databases or message queues or email servers and also, they need to call other applications. For example, they might need to call web services. Now usually when we have credentials for databases or URLs that connect it to specify message queues and such then we usually do not hardcode that in our code. So, for this we use external configuration to dynamically adjust the application behavior to describe where the resources are located and how to connect to a database.
Different configuration options available:
Package configuration files with Application: One of the things we can do is to externalize the configuration from our code and put it in our configuration file and we can package that with our application. In this case, if you have any kind of change to your application configuration, then you need to rebuild your application and then redeploy. So, it is not the most dynamic way.
Use Environment Variable: We can use environment variables as a configuration option. This env. Variables work differently in different platforms. If we have a large number of individual variables, then it is very difficult to manage. It is also difficult to duplicate. We could miss any env. Variable. So, it is problematic.
Use Cloud-vendor specific Solution: Suppose for example, if we are using PCF(Pivotal cloud foundry) as your cloud env, then we can use their “v_cap services” variable. So, here we will be coupling our application to a specific environment. So, if I am running my app on cloud foundry, then I would have to have a library that would know how to interpret the cloud foundry specific settings and make it available to my application.
Challenges for application configuration:
Microservice: when we have Microservice apps, then we have a large number of dependent services and then we will have a greater need for the application configuration. If we manually setup our relationships between different services, then there is a lot of manual work we have to do.
Dynamic Updates: Dynamic update means if we are making changes to our configuration, then we can do it automatically and our application will automatically pick up the changes, now when we use environment variables, our application code can get the new changes and rebuild the app and then redeploy.
Version control: It is always nice to have some trackability when we are talking about configuration changes. If we have version control, then we can put our configuration changes in version control as it is just a simple file then it is really easy to have the traceability.
Desired Solution for Configuration Management:
These are the things exactly that the Spring cloud is going to come in.
Spring Cloud Config: It is for providing a centralized location for applications to get their configuration information. It is externalized from the applications Spring cloud config provides externalized secured and easy-to-reach source of application configuration.
Spring cloud bus: This is going to provide a simple way to push changes out and to notify clients about the config changes. Cloud bus provides a simple way to push dynamic changes out and
Spring Cloud Netflix Eureka: This is about service discovery and it allows applications to register themselves as up and ready to go.
Spring cloud-config is simply an application that is designated as a centralized server that serves up configuration information. The configuration information itself is backed by some kind of source control. The idea with spring cloud-config is that the client applications can connect over HTTP and they can retrieve their configuration settings when they startup. They can do this in addition to their internal sources of configuration be it internally package files or environment variables.
Please look at the above image, we have config server and few spring client applications that are connecting to the config server. The config server is something that we can run multiple copies of it. We can put this behind the load balancer which I have not mentioned here. The config server can serve up configuration information that comes from backing files on many different sources. There are two sides to a spring cloud-config. There is a spring cloud config server and there is a spring cloud config client.
Config server is available in the GitHub URL mentioned below:
The Server Side configurations and code:
I am going to show you how to build your config server. Now, let’s start by building a spring boot project and then altering the dependencies slightly. For the parent, we need to change the group id to “org.springframework.cloud” and change the artifact to “spring-cloud-starter-parent”. Put the latest version of spring cloud. Once, the parent is established, then there is one dependency that we have to add is “spring-cloud-config-server”. This contains all the libraries needed to support the running of a config server.
Now, we need to specify in the spring cloud config server’s internal configuration file (“application.yml” file) where it should go and when it needs to find the actual config info. Itself that needs to be served up. In this application yaml file, the spring cloud config server is using a git URI so that it will go out to GitHub to obtain the config. Information.
Note: We can use application .properties file also to do the same thing.
The next step is: In your spring boot application, in one of your configuration classes such as your main application class, just add annotation “@EnableConfigServer”
The Client-Side configurations and code:
On the client-side, you can switch the parent pom the same by doing the boot-cloud replacement. But this might not be desirable in all situations. You may already be using the parent pom for a different purpose. So, if you would not change the parent pom, then as I told earlier, you can add a “dependency management” section with the spring cloud starter parent. Refer to the earlier snapshot.
Spring cloud starter brings in the basic spring cloud dependencies and this is the only dependencies we need on the client-side.
Next, there are 2 properties that we need to configure as soon as the server starts up. These two properties are the name of our application and the location of the config server.
These details require to be loaded early, we will put these in the “bootstrap.properties or yaml file. In spring cloud, the application context is initially loaded by using the bootstrap.properties file and it connects to the config server to obtain additional properties and then these values are used to control a separate application context i.e. loaded using the application.properties file. So, there are two application contexts loaded and one is for bootstrapping the application and then the other is the main startup file that happens afterward.
The client will connect at startup time and then contribute the discovered properties to the main application context when it starts.
Spring cloud config server uses an abstraction (an interface actually) called “EnvironmentRepository”. Two implementations are available to us in spring cloud config are
Native implementation ( means local files or flat files)
Now, if you have a different source control system, then you need to provide your implementation for environment repository. In a repo, we will put flat files.
The config files that we can place in the repo. Are expected to abide by a naming convention. The basic part of the naming convention is that a file should be named after the spring application name that it corresponds to. It will be as below :
The spring.application.name is the property that is set by the client application bootstrap yaml or properties file. The “profile” is the client application’s active profile i.e. spring.profile.active
The next part is to obtain the settings from the server. The client application is actually going to make an HTTP call and it is going to call the server and port that we specify and it will use its application name as a key and then it will add the active profile. Structure will be like below:
Note: If there are no active profile, then it will take the default profile. Spring clients do this automatically on startup.
Environment Repository Example:
Let’s assume that we have a client application and its name is “cloud-demo” and the profile name is “dev”. So, the file name will be “cloud-demo-dev.yml”. Now, when the spring cloud config server consults the file in the repository, it will look for files that match the application name and the profile specified.
Note: In YAML format of the file, it can hold multiple properties within a single file. If we use properties file, then for two different profiles, we have to create two properties file but the same can be done in the same yaml file.
How Properties work in Spring Application: Every Spring application context has an “Environment” object in it that is populated by the container. Environment object contains multiple “PropertySources”. Propertysource is nothing but a source of property that came from somewhere. Now Spring application context will automatically populate property sources from the environment variables where an app is running and from the system properties that we specify when we launch the app. Also, we can specify our property source to pick up the external property files.
When the spring app starts up and it uses spring cloud config on a client-side, then the library simply alters the set of behaviors just to add another property source and it populates that property source by connecting to the server over HTTP using the below URL and getting the response back and populating the property source :
Properties that are described by the server become part of the client application environment.
Note: Spring cloud server exposes properties over a restful interface using HTTP. It is reasonably easy to make this call to the server from any application.
What if Config server is Down?
In Microservice Applications, when we have different Microservice, talking to each other and if config server is down, then this will create a big problem. Actually, Spring cloud config server is recommended to be run in multiple instance. So, if we are running on cloud foundry or AWS, then we will have several instances running behind a load balancer.
Client application can specify the ultimate policy of how to handle the missing config server. There is a setting called “spring-cloud .config.failFast=true”. The default value is false. The default is that we do not want to fail. The client does not want to fail. And if we do not want this behavior then we can set failFast to true and this will make the client not to run without config server being provided. Config server setting overrides any local settings that we have. We can provide local fallbacks for our settings then we can have the config sever override this.
Read more - How to Setup SPRING CLOUD CONFIG
Config Server creation:
First, create a normal spring boot maven project. I believe you are more familiar with the basic spring boot applications. I have named the project “config-1-server” and also have used this as the Artifact value.
Please go to your POM file and add a “Dependency Management” section after
Then, need to add a dependency for the group "org.springframework.cloud" an artifact "spring-cloud-config-server". Version is not required to mention as this is already mentioned in the spring-cloud-dependencies POM. Added the below dependency in my pom:
Now, I have created the main Application class (DemoApp.java). Please see the below class. I have added the @EnableConfigServer to this class.
Then under this “ConfigurationData “repo, I have added a new file named "demo-client.yml”. This file contains a key called "country-word" and value of "Indian”. You can give your own key-value pairs of your choice.
Now, let’s move back to our spring boot project and will create an “application.yml” file in my classpath root (under src/main/resources). Need to specify the key "spring.cloud.config.server.git.uri" and the value "https://github.com/"YOUR-GITHUB-ID"/ConfigurationData". “ConfigurationData” is our repo. Name here.
Note: You can create “application.properties” file also. Either of these is fine. I have set the “server.port” to 8001.
We can test our application by running the application. Open up your browser and hit the URL “http://localhost:8001/demo-client/default/”. You will be able to see the JSON response in the browser i.e. actually used by Spring. If any issue, then you should check your project setup.
Config Client creation:
Now, let’s create a new, individual Spring Boot application and this will be a client app with a name the project is “config-1-client ". We have to use this same project name value for the Artifact. Also, I have added spring-boot-starter-web dependency.
Then, we have to add a “Dependency Management” section the same as what we did for our “config-1-server” project’s pom file to identify the spring cloud parent pom.
Then, need to add a dependency for the group "org.springframework.cloud" an artifact "spring-cloud-starter-config”. I have not specified a version as this is already defined in the parent pom’s dependency management section. below dependency we have to add:
Now, we have to create a bootstrap.yml file (or bootstrap.properties) file in my class path root (under src/main/resources). In spring cloud, the application context is initially loaded by using the bootstrap.properties file and it connects to the config server to obtain additional properties
I have added the following configurations in my bootstrap.yml file.
Note: The server.port config value can be specified in either file (the application.yml or bootstrap.yml), but the URI to the config server must be specified in bootstrap.yml as it affects the startup sequence
Now, we have to create a Rest controller class (“MyController.java) to obtain the key-value pair that we have specified in our demo-client.yml file. In this class, I have a Get mapping method named showWord() which will fetch the value of the “country-word” key.
Now, we can verify our rest end-point by accessing the below URL to get the “country-word” value displayed in the browser. Also, you can test in your postman
Configuration with Spring Profiles:
Now, to test with the spring profiles, let’s create a separate file. So, in my same GitHub repository “ConfigurationData “, I have created a file called "demo-client-dev.yml” (or you can create with .properties). I have specified it with the "country-word" key and a different value to differentiate it from our original file (demo-client.yml).
Now, we have to stop our client application “config-1-client”. Then only I can modify the original bootstrap yaml file to contain a key of “spring.profiles.active: dev” (This type of key-value pair is for .properties format). Then after modifying the file with new profile configuration, we have to restart your client app.
Updated bootstrap.yml file:
Now, we can verify our same rest end-point by accessing the URL(URL: http://localhost:8002/country-word) to get the “country-word” new value as “India-Profile” should be displayed in the browser. Also, you can also test the same URL in your postman
Note: Without updating our bootstrap.yml file with adding the “dev” profile, we can achieve the same result by just running our application with the below command-line arguments
Summary: So, you noticed here that the client needed some dependencies for Spring Cloud that Java programmer provided in our application’s pom file and in our bootstrap file, only we specified the URI of the Spring Cloud server. No java code we had to write for this. So, how easy it is to configure without writing any code for this. This Springe cloud config server is a powerful feature and is more helpful in Microservice oriented applications.
Here, I have explained to you about the Spring cloud configuration with an example. But more advanced concepts I will be explaining in our other blogs with how Spring Cloud Bus and refresh scope can be used to dynamically propagate changes in the scenarios where we change a property after client applications have already started. It is very natural that behind a load balancer, we can run multiple instances of the config server in multiple zones.