Enterprise Java

Using @ConfigurationProperties in Spring Boot

logo-spring-io

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 and PROTOCOL will be bind to protocol field of a bean
  • smtp-auth, smtp_auth, smtpAuth will be bind to smtpAuth field of a bean
  • smtp.auth will be bind to … hmm to smtp.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 @ConfigurationPropertiesso 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 @Beans 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@Autowireto 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 @EnableConfigurationPropertiesannotation. 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.

Reference: Using @ConfigurationProperties in Spring Boot from our JCG partner Rafal Borowiec at the Codeleak.pl blog.

Rafal Borowiec

Software developer, Team Leader, Agile practitioner, occasional blogger, lecturer. Open Source enthusiast, quality oriented and open-minded.
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
Stephane Nicoll
Stephane Nicoll
9 years ago

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

DILLIBABU MEKALA
DILLIBABU MEKALA
5 years ago

@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.

Back to top button