Enterprise Java

HANDLING CONFIGURATIONS IN SPRING BOOT

I am currently getting back to coding in Java + Spring after about 8 years. In the last 8 years, the time I spent on coding has gone significantly as I am now into leadership roles that take me away from writing code. Having said that, I need to understand some level of coding, especially in the Java world, as that’s the language in which I find most of my projects, and I cannot help my teams effectively unless I am familiar with coding. So much has changed since I stopped coding, and I am learning everything again. This is the first of the many articles I will write to get as I know new things. Also, I am building an application more from my personal fruition. I generally cannot spend consistent time, which allows me to spend more time learning instead of trying to meet the deadlines of an actual life client project.

In this post, I will talk about how to use externalize configurations in a Spring Boot application.

1. Overview

We will use Spring Boot’s default setup to create some configurations and read them in our application. We will also look at a simple key-value way of setting up properties and YAML based configurations.

I prefer using YAML and from this point onwards I will only be using YAML bases setups.

2. Initial Setup

During my implementation run, I noticed that I was eventually required to use the spring-boot-configuration-processor dependency. Else I would get an error, and the code would not compile. I didn’t find much on why this is needed in my research, but adding this dependency resolved the issue for me.

The second dependency I have added is for Actuator, which gives us some exciting tools. This is unnecessary, but if you are looking to debug your properties and find more configurations to work with, I will suggest you add this as well.

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

3. Setting up Configuration Files

The following code is for application.properties file which is the default format you will get in Spring Boot.

# This is to expose all the endpoints for Actuator. use * for all ONLY in DEV
management.endpoints.web.exposure.include=*

# Custom Properties
bungie.rootPath="https://www.bungie.net/Platform"
bungie.apiKey=000999888111

The following is same properties for in YAML format.

bungie:
  rootPath: "https://www.bungie.net/Platform"
  apiKey: 000999888111

4. Creating the Bean that will read these configurations

Now that we have created the properties, we have 2 use cases that we need to consider when reading the properties.

  • Reading One off property – In this case, we may need to create a property that needs to be read once or can’t be categorised with any other property. In this case, you can use the @Value annotation to read it.
  • Reading a set of properties – In our example, we have already identified two grouped properties under the “bungie” category. This is how I prefer to create properties. I do not like having orphan properties, and hence we will only see how to set these up. The following example will show us creating a Java Bean/Configuration, which will be able to read our property file and populate the object.
package io.howtoarchitect.destinyclanwars.config;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConfigurationProperties("bungie")
@Getter @Setter
public class BungieClientSettings {
    private String rootPath;
    private String apiKey;
}

If you observe the code block above, you will notice a few things:

  • We have used @Configuration to let the Spring application know that this is a bean and should be initialised as such
  • @Getter and @Setter are from the Lombok package, giving us default Getters and Setters. These are mandatory as Spring application will always need these getters and setters.
  • @ConfigurationProperties is the annotation that does the main trick here. It will go through all the properties available in our context and will search for any that have been mapped user “bungie”. Once found, this annotation will map the YAML/Properties file values and add them to our strings.

5. Consuming Properties

Once you have this setup, the last step is to read these properties in our application. We will be reading these properties in another Spring bean/service.

package io.howtoarchitect.destinyclanwars.bungieclient;

import io.howtoarchitect.destinyclanwars.config.BungieClientSettings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

@Service
public class BungieClient {
    private static WebClient client;

    @Autowired
    private BungieClientSettings bungieClientSettings;

    public WebClient getDefaultClient() {
        client = WebClient.builder()
                .baseUrl(bungieClientSettings.getRootPath())
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .defaultHeader("X-API-KEY", bungieClientSettings.getApiKey())
                .build();

        return client;
    }
}

You will notice that I have added BungieClientSettings as an @Autowired dependency. This injects the bean in my class, and when I need to access these properties, all I need to do is bungieClientSettings.getAPIKey() and bungieClientSettings.getRootPath().

Conclusion

This is all you need to do is to externalise your properties. This is important to set up early on because if you do not, you will end up having many of these scattered in classes, and moving across to multiple environments will become hard.

In next few articles, we will look at

  1. How to use environment-based configuration. In my case, I will have different keys for development and production, and I will be able to handle the same.
  2. Use Spring’s cloud configuration Server, which will allow us to centralise our configurations into 1 project and also be able to swap designs without having to deploy the code (Configuration as Code pattern).
  3. Finally, we will look at how can we secure some of these properties via encryption. For example, my apiKeys need to be confirmed. I have used random values in the samples that I have given, but in my application, I need keys to be valid and not exposed via GITHUB repo plain text files.

Published on Java Code Geeks with permission by Kapil Viren Ahuja, partner at our JCG program. See the original article here: HANDLING CONFIGURATIONS IN SPRING BOOT

Opinions expressed by Java Code Geeks contributors are their own.

Kapil Viren Ahuja

Kapil Viren Ahuja is a Senior Manager, Technology from SapientNitro’s Gurgaon Office. Kapil is the solution architect working on Digital Marketing Platforms and has worked for accounts including NASCAR, Richemont, Alex and Ani. Kapil has also been the Lead Architect on the SapientNitro’s EngagedNow platform. In his role Kapil is responsible for driving technical solutions and delivery on various projects. Kapil over the course of his 15 years of total experience has worked on several technologies spanning from Enterprise technical stacks to CMS to Experience technologies. Kapil is also an evangelist of new technologies and loves to go beyond the same old day to day work and find new and innovative ways to do the same things more effectively.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Marc Vb
Marc Vb
2 years ago

The example is to small to be good. You wil never have an application that simple

ruurd
ruurd
2 years ago

Issues: Advocate yaml as property format. The format is much stricter and better organized than properties. Instead of @Getter and @Setter use @Data Don’t @Autowire. Make what you want to inject private final (you don’t want to be able to modify injected objects anyway) and add @RequiredArgsConstructor I don’t have the foggiest idea why you are using that private static for in the first case. @Service objects are singletons anyway. I would use the BungieClientProperties class, inject that into a BungieClientConfiguration class that can provide a WebClient as a bean or even an extended WebClient class. This way I can… Read more »

Last edited 2 years ago by ruurd
Back to top button