in Java, Spring

Using @ConfigurationProperties to separate service and configuration

Roughly about two years ago, I wrote an article called “Why using Spring’s @Value annotation is bad“. I described why you should avoid @Value annotations all throughout your code. By using @Value annotations in services, controllers and other Spring components, you will scatter your configuration through the complete application. In the worst case, you will wire the same value in multiple classes. If you want to change this value somedays, you will need to touch all of this classes.

Instead of this, configuration should be an encapsulated aspect of your application just like database access or REST endpoints. We want to separate configuration from our actual services, controllers and components.

The Spring Boot way to do it

Spring Boot provides an annotation called @ConfigurationProperties. As you can read right here, it’s exactly designed to separate and externalize configuration. That’s what we want!

Let’s make an example and assume that we want to configure a connection to an external REST service (it could also be a database or whatever). We need a configuration including an username, a password and an URL. The configuration file (application.properties) could look like this:

By using Spring Boot’s @ConfigurationProperties annotation, we would first write a Java class which represents this piece of configuration:

As you can see, we have a very obvious matching between the properties file and its Java representation. Let’s see how we would use this class:

As you can see, we encapsulated all configuration in a single class which we inject in our service. The service doesn’t know anymore where the configuration comes from. It only knows that it can receive the configuration from the MySuperServiceConfig class. Separation completed!

What else can we do?

We have not only just separated our configuration, but we have transformed it into a Java class! This means we can just code with it! Here some examples and ideas:

Apply default values

We can just apply default values for properties which should be configurable but are not likely to be configured. Let’s say we have a port:

In most cases, the port will be 8080. Only in some rare circumstances, we will have another port – maybe in our test system. In this case, we can just apply a default:

Process configurations

Let’s assume the following configuration:

For some reason, we want to be able to configure each property on its own. However, in the service we need to have a single url: http://some.where.com:8080/api/v1. We can do this in our configuration class!

Create different implementations

Our configuration just became a Spring Bean. This also means, that we can do all the common Spring things with it! For example creating different implementations.

By doing this, we end up with a solution similar to what I’ve described in “Why using Spring’s @Value annotation is bad“. The configuration becomes a service which we hide behind an interface. We can change how we get the configuration (from a properties file, hard coded or from our configuration server in the cloud) and how we map and process it. Our actual services will only contain business logic and will not have to deal with configuration issues.

Best regards,
Thomas

More

Write a Comment

Comment