Using @ConfigurationProperties in Spring Boot
In my latest blog post I described shortly how one can configure mail in Spring Boot application. To inject properties into the configuration I used Spring’s @Value
annotation. But Spring Boot provides an alternative method of working with properties that allows strongly typed beans to govern and validate the configuration of your application. In this post I will demonstrate how to utilize @ConfigurationProperties
while configuring the application.
So we want to use the mail configuration as an example. The configuration file is placed in a separate file, called mail.properties
. The properties must be named using a proper convention, so they can be bind properly. Let’s see some examples:
protocol
andPROTOCOL
will be bind toprotocol
field of a beansmtp-auth
,smtp_auth
,smtpAuth
will be bind tosmtpAuth
field of a beansmtp.auth
will be bind to … hmm tosmtp.auth
field of a bean!
Spring Boot uses some relaxed rules for binding properties to @ConfigurationProperties
beans and supports hierarchical structure.
So let’s create a @ConfigurationProperties
bean:
@ConfigurationProperties(locations = "classpath:mail.properties", ignoreUnknownFields = false, prefix = "mail") public class MailProperties { public static class Smtp { private boolean auth; private boolean starttlsEnable; // ... getters and setters } @NotBlank private String host; private int port; private String from; private String username; private String password; @NotNull private Smtp smtp; // ... getters and setters }
… that should be created from the following properties (mail.properties
):
mail.host=localhost mail.port=25 mail.smtp.auth=false mail.smtp.starttls-enable=false mail.from=me@localhost mail.username= mail.password=
In the above example, we annotated a bean with @ConfigurationProperties
so that Spring Boot can bind properties to it. ignoreUnknownFields = false
tells Spring Boot to throw an exception when there are properties that do not match a declared field in the bean. This is pretty handy during the development! prefix
let you select the name prefix of the properties to bind.
Please note that setters and getters should be created in @ConfigurationProperties
bean! And opposite to @Value
annotation it may bring some extra noise to the code (especially in simple cases, in my opinion).
Ok, but we want to use the properties to configure our application. There are at least two ways of creating @ConfigurationProperties
. We can either use it together with @Configuration
that provides @Bean
s or we can use it separately and inject into @Configuration
bean.
The first scenario:
@Configuration @ConfigurationProperties(locations = "classpath:mail.properties", prefix = "mail") public class MailConfiguration { public static class Smtp { private boolean auth; private boolean starttlsEnable; // ... getters and setters } @NotBlank private String host; private int port; private String from; private String username; private String password; @NotNull private Smtp smtp; // ... getters and setters @Bean public JavaMailSender javaMailSender() { // omitted for readability } }
In the second scenario, we simply annotate the properties bean (as above) and use Spring’s@Autowire
to inject it into mail configuration bean:
@Configuration @EnableConfigurationProperties(MailProperties.class) public class MailConfiguration { @Autowired private MailProperties mailProperties; @Bean public JavaMailSender javaMailSender() { // omitted for readability } }
Please note @EnableConfigurationProperties
annotation. This annotation tells Spring Boot to enable support for @ConfigurationProperties
of a specified type. If not specified, you may otherwise see the following exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [demo.mail.MailProperties] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Just a note: there is other way (there is always other way with Spring Boot!) to make that @ConfigurationProperties
annotated beans will be added – just add @Configuration
or @Component
annotation to the bean, so it can be discovered during component scan.
To sum up, @ConfigurationProperties
beans are pretty handy. Is it better than using @Value
annotation? In certain scenarios probably yes, but this is just the choice you need to make.
- Have a look at Spring Boot’s documentation to read more about typesafe configuration properties: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-typesafe-configuration-properties
Reference: | Using @ConfigurationProperties in Spring Boot from our JCG partner Rafal Borowiec at the Codeleak.pl blog. |
Thanks for the article. A few additional notes:
The “locations” attribute is an optional thing. When you work with such an infrastructure, you usually rely on the Environment to provide you the keys (i.e. Env variables, System properties, command-line switch or applications.properties (or yml).
If you add an optional dependency to the “spring-boot-configuration-processor”, your module will hold a meta-data file that is generated at compile time with details about your properties. IDEs can then pick that up to show you content assist. STS, Intellij IDEA and Netbeans have such support. More info here: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#configuration-metadata
@ConfigurationProperties(locations = “classpath:mail.properties”, ignoreUnknownFields = false, prefix = “mail”)
Here locations attribute is not avail can you please help me out on this to import multiple files in spring boot.
Example:
I have tried
@PropertySources({ @PropertySource(value = “classpath:dev/application-dev.yml”),
@PropertySource(value = “classpath:uat/application-uat.yml”)
})
@ConfigurationProperties(prefix = “db”)
It is not working and i got to know that we need to provide the file locations to spring boot annotation instead of spring annotation.
@ConfigurationProperties(locations= “{classpath:dev/application-dev.yml,
classpath:dev/application-uat.yml}”, prefix = “db”)
This is also not working by saying unknown attribute ‘locations’.
Please help me on this.