Configuring Properties with Spring Boot

Learn to use @PropertySource, @Value and @ConfigurationProperties annotations to register property files and inject property values into a Spring boot application’s configuration.

1. Register Properties Files with @PropertySource

The @PropertySource annotation is used to register the property files in a Spring application.

1.1. Spring Boot Automatically Loads application.properties

By default, Spring Boot automatically loads the application.properties whenever it starts up. We can access the properties defined in application.properties using @Value annotation.

Let us assume that we have the following application.properties file.

application.name=Demo App

If we have to access this property in a Spring @Component, we can use the @Value annotation.

@Component
//This is optional as Spring boot loads application.properties by default
@PropertySource("classpath:application.properties")
public class AppProperties {

  @Value("${application.name}")
  private String appName;
}

In addition to application.properties, Spring boot automatically loads the profile-specific property file. For example, if the active profile is dev then Spring boot will load the application-dev.properties file along with application.properties file.

If there are any conflicts between values in the two files, then the profile-specific file wins. Ideally, we should specify the default values in application.properties and override them with profile-specific values in application-dev.properties file.

1.2. Loading Custom Properties Files

If we want to change which file Spring Boot reads by default then we can use the spring.config.name property.

export SPRING_CONFIG_NAME=foo

Now when we run the spring boot application, it will load all the properties from foo.properties file.

If we have a different properties file or multiple properties files, then we can explicitly use the @PropertySources annotation to specify those property files. Specifying application.properties is optional in this case, too.


@Component
@PropertySources({
    @PropertySource("classpath:jms.properties"),
    @PropertySource("classpath:datasource.properties")
})
public class AppProperties {
	//...
}

1.3. Duplicate Property Resolution

This is important to note that if there are two or more properties with the same name then the property value will be chosen from the last occurrence of the property file.

Duplicate property values do not raise any exceptions.

2. Inject Property Values with @Value

The @Value is used at the field or method/constructor parameter level to initialize the field with a default value expression populated from the property file.

  • SpEL (Spring Expression Language) expressions can be used to inject values using #{systemProperties.myProp} syntax.
  • Property values can be injected using ${my.app.myProp} style property placeholders.

Also, we can assign a default value to a property key. This helps in preventing the exception when the property key is missing or not found in the properties file.

@Component
@PropertySources({
    @PropertySource("classpath:jms.properties"),
    @PropertySource("classpath:datasource.properties")
})
public class AppProperties {

  @Value("${application.name:My App}")
  private String appName;

  @Value("${spring.datasource.url}")
  private String datasourceUrl;
}

To insert a list of values in a String array or List, we can use the following example. For reference, the property name and value are:

app.environments=local,dev,test,prod

Injecting such values into String array is supported, by default.

@Value("${app.environments}")
private String[] environments;

To inject these values into a List, we need to use the SpEL syntax.

@Value("#{'${app.environments}'.split(',')}")
private List<String> environmentsList;

3. Bind Fields to Property Values with @ConfigurationProperties

The @ConfigurationProperties is used to bind the member fields in a bean with the property values defined in a properties file. Binding is either performed by calling setters on the annotated class or, if @ConstructorBinding is in use, by binding to the constructor parameters.

Note that contrary to @Value, SpEL expressions are not evaluated since property values are externalized.

For example, suppose we have the following properties in application.properties file.

spring.datasource.url=jdbc:h2:file:C:/temp/test
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.dialect=org.hibernate.dialect.H2Dialect

To bind these properties in class fields, we need to create fields with the exactly same name as the property name. Also, we must mention the prefix, if any.

@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource")
public class DatasourceProps {

  private String url;
  private String username;
  private String password;
  private String driverClassName;
  private String dialect;
}

If the above properties are part of a separate file datasource.properties, then we can use @PropertySource to specify the property file name.

@Data
@Component
@PropertySource("classpath:datasource.properties")
@ConfigurationProperties(prefix = "spring.datasource")
public class DatasourceProps {

  //fields
}

4. Validate Property Values

Start with importing spring-boot-starter-validation module in the project. This module imports the hibernate-validator project that implements the JSR-303 specification.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

For validating the field-property bindings, we can use @Validated annotation. It is a variant of JSR-303’s @Valid, supporting the specification of validation groups.

In addition to @Validated, we need to apply specific constraints on the fields using the javax.validation.constraints annotations. If any of these validations fail, then the application would fail to start with an IllegalStateException.

@Data
@Component
@Validated
public class AppProperties {

  @NotEmpty
  @Value("${application.name}")
  private String appName;

  @NotEmpty
  @Value("${spring.datasource.url}")
  private String datasourceUrl;
}

5. Include Additional Configuration Files

To include additional property files, we can use the spring.config.import property within the application.properties or application.yml file. Imports are processed as they are discovered, and are treated as additional documents inserted immediately below the one that declares the import.

For example, we can have the following import statement in application.properties file.

application.name=Demo App
spring.config.import=optional:file:./dev.properties

The above import will try to search and import the dev.properties file in the current working directory. If the file is found then its values will take precedence over the file that triggered the import. If the file is not found then no error is reported.

Note that the position of spring.config.import statement in the existing property file does not matter. It will always produce the same result, as discussed above.

If we specify multiple locations then all the locations will be processed in the order that they are defined, with later imports taking precedence. We can also specify a directory containing multiple property files.

spring.config.import=classpath:datasource.properties,
										  classpath:mysql-properties.yml,
										  optional:file:./cloud-deployment.properties,
										  classpath:test-properties/

If a directory is imported then loaded files are sorted alphabetically. If we need a different order, then we should list each location as a separate import.

The spring.config.import property can be set using the server startup arguments as well:

$ java -jar myproject.jar --spring.config.import=\
    classpath:datasource.properties,\
    classpath:mysql-properties.properties,\
    optional:file:./cloud-deployment.properties,\
    classpath:test-properties/

7. Conclusion

In this tutorial, we learned to import and register default property files as well as multiple custom property files using @PropertySource and @PropertySources annotations. We learned to bind the fields with property values using @ConfigurationProperties annotations.

We learned to validate the property values during application startup and even specify optional values if a corresponding property name is not found.

Happy Learning !!

Sourcecode on Github

Was this post helpful?

Join 8000+ Awesome Developers, Like YOU!

Leave a Comment

About HowToDoInJava

This blog provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions, and frequently asked interview questions.