Spring Boot makes is very easy to read values from an external properties file. Without having to do any configuration, you are able to inject values to instance fields using the
@Value annotation or using Spring’s
Environment abstraction. But both of these solutions require you to specify the property value as a string. Spring Boot also provides a type-safe way to handle configuration by allowing you to create a bean and populating it with property values from your configuration file.
Let’s have a look at the following example
application.yml file (this will work with a
.properties file as well).
This configuration file has three properties nested under the
application namespace. The following is a Java class declaring these properties as instance variables.
Observant readers noticed that this class is annotated with
@ConfigurationProperties("application"). This instructs Spring Boot to bind property values from your configuration file to instance fields.
"application" specifies that only properties with the given prefix should be bound to this object.
Before you can start injecting
@ConfigurationProperties beans you need to enable configuration properties by adding
@EnableConfigurationProperties(ApplicationProperties.class) to a configuration bean.
Now that this is done, feel free to inject
ApplicationProperties as you would inject any other bean.
Having configuration properties defined in a bean enables you to validate them using Java Bean Validation. Let’s say the
servicePassword property must always be defined. Otherwise your application’s state is invalid. That can be easily achieved by annotating the field with
If the application is started with an
applicaiton.yml that does not include
servicePassword, Spring Boot throws an exception on startup and the application fails to start.
What if I add another level of nesting into my
applicaiton.yml file? Can I still use my
ApplicationProperties as a single source of configuration values? The answer to this question is yes. But you need to do some modifications first. In the following example, the application has been configured with a
To access that from Java, you need to create a new class for each level of nesting. In this case, you would need to create a new static inner class for the
remoteHost field and include all of it’s sub-fields as instance variables. The following is the updated
Spring Boot will take care of instantiating the inner class. In your application code, you can access the newly added property by calling
@ConfigurationProperties allows you to manage configuration values in a type-safe manner. Refactoring is made easier for you since you have a single class where all property values are defined. Consider the
@Value annotation for a moment. Injecting a property using
@Value requires you to specify the property as a string. What if you have multiple places in your codebase where this property is used? If your IDE is not smart enough, you would need to do a project wide search and replace when renaming a single property in the properties file.
I hope you gained some new ideas reading this. A class holding all configuration values has its merits, namely, type-safety, advantages in refactoring and validation can be in one place. But don’t go and start replacing all of your
@Value annotations with configuration classes just yet. Use common sense. Sometimes it is less work to just use
@Value or Spring’s