Spring Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

This tutorial will show how to set up and use properties in Spring via Java configuration and @PropertySource or via XML and <property-placeholder>.

We'll also see how properties work in Spring Boot.

Further reading:

Spring Expression Language Guide

This article explores Spring Expression Language (SpEL), a powerful expression language that supports querying and manipulating object graphs at runtime.

Configure a Spring Boot Web Application

Some of the more useful configs for a Spring Boot application.

Guide to @ConfigurationProperties in Spring Boot

A quick and practical guide to @ConfigurationProperties annotation in Spring Boot.

2. Register a Properties File via Java Annotations

Spring 3.1 also introduces the new @PropertySource annotation as a convenient mechanism for adding property sources to the environment.

This annotation is to be used in conjunction with Java-based configuration and the @Configuration annotation:

@Configuration
@PropertySource("classpath:foo.properties")
public class PropertiesWithJavaConfig {
    //...
}

Another very useful way to register a new properties file is using a placeholder, which allows us to dynamically select the right file at runtime:

@PropertySource({ 
  "classpath:persistence-${envTarget:mysql}.properties"
})
...

2.1. Defining Multiple Property Locations

The @PropertySource annotation is repeatable according to Java 8 conventions. Therefore, if we're using Java 8 or higher, we can use this annotation to define multiple property locations:

@PropertySource("classpath:foo.properties")
@PropertySource("classpath:bar.properties")
public class PropertiesWithJavaConfig {
    //...
}

Of course, we can also use the @PropertySources annotation and specify an array of @PropertySource. This works in any supported Java version, not just in Java 8 or higher:

@PropertySources({
    @PropertySource("classpath:foo.properties"),
    @PropertySource("classpath:bar.properties")
})
public class PropertiesWithJavaConfig {
    //...
}

In either case, it's worth noting that in the event of a property name collision, the last source read takes precedence.

3. Register a Properties File in XML

In XML, new properties files can be made accessible to Spring via the <context:property-placeholder … > namespace element:

<context:property-placeholder location="classpath:foo.properties" />

The foo.properties file should be placed under /src/main/resources so that it will be available on the classpath at runtime.

In case multiple <property-placeholder> elements are present in the Spring context, there are a few recommended best practices:

  • The order attribute needs to be specified to fix the order in which these are processed by Spring.
  • All property placeholders minus the last one (highest order) should have ignore-unresolvable=”true” to allow the resolution mechanism to pass to others in the context without throwing an exception.

3.1. Register Multiple Properties Files in XML

In the previous section, we saw how to define multiple properties files using annotations in Java 8 or later.

Similarly, we can define multiple properties files using XML configuration:

<context:property-placeholder location="classpath:foo.properties, classpath:bar.properties"/>

And as before, in the event of a property name collision, the last source read takes precedence.

4. Using/Injecting Properties

Injecting a property with the @Value annotation is straightforward:

@Value( "${jdbc.url}" )
private String jdbcUrl;

We can also specify a default value for the property:

@Value( "${jdbc.url:aDefaultUrl}" )
private String jdbcUrl;

And we can do the same using XML configuration:

<bean id="dataSource">
    <property name="url" value="${jdbc.url}" />
</bean>

Both the older PropertyPlaceholderConfigurer and the new PropertySourcesPlaceholderConfigurer added in Spring 3.1 resolve ${…} placeholders within bean definition property values and @Value annotations.

Finally, we can obtain the value of a property using the Environment API:

@Autowired
private Environment env;
...
dataSource.setUrl(env.getProperty("jdbc.url"));

A very important caveat here is that using <property-placeholder> will not expose the properties to the Spring Environment.

This means that retrieving the value like this will not work — it will return null:

env.getProperty("key.something")

5. Properties With Spring Boot

Before we go into more advanced configuration options for properties, let's spend some time looking at the new properties support in Spring Boot.

Generally speaking, this new support involves less configuration compared to standard Spring, which is of course one of the main goals of Boot.

5.1. application.properties: the Default Property File

Boot applies its typical convention over configuration approach to property files. This means that we can simply put an application.properties file in our src/main/resources directory, and it will be auto-detected. We can then inject any loaded properties from it as normal.

So, by using this default file, we don’t have to explicitly register a PropertySource or even provide a path to a property file.

We can also configure a different file at runtime if we need to, using an environment property:

java -jar app.jar --spring.config.location=classpath:/another-location.properties

As of Spring Boot 2.3, we can also specify wildcard locations for configuration files.

For example, we can set the spring.config.location property to config/*/:

java -jar app.jar --spring.config.location=config/*/

This way, Spring Boot will look for configuration files matching the config/*/ directory pattern outside of our jar file. This comes in handy when we have multiple sources of configuration properties.

5.2. Environment-Specific Properties File

If we need to target different environments, there's a built-in mechanism for that in Boot.

We can simply define an application-environment.properties file in the src/main/resources directory, and then set a Spring profile with the same environment name.

For example, if we define a “staging” environment, that means we'll have to define a staging profile and then application-staging.properties.

This env file will be loaded and will take precedence over the default property file. Note that the default file will still be loaded, it's just that when there is a property collision, the environment-specific property file takes precedence.

5.3. Test-Specific Properties File

We might also have a requirement to use different property values when our application is under test.

Spring Boot handles this for us by looking in our src/test/resources directory during a test run. Again, default properties will still be injectable as normal but will be overridden by these if there is a collision.

5.4. The @TestPropertySource Annotation

If we need more granular control over test properties, then we can use the @TestPropertySource annotation.

This allows us to set test properties for a specific test context, taking precedence over the default property sources:

@RunWith(SpringRunner.class)
@TestPropertySource("/foo.properties")
public class FilePropertyInjectionUnitTest {

    @Value("${foo}")
    private String foo;

    @Test
    public void whenFilePropertyProvided_thenProperlyInjected() {
        assertThat(foo).isEqualTo("bar");
    }
}

If we don't want to use a file, we can specify names and values directly:

@RunWith(SpringRunner.class)
@TestPropertySource(properties = {"foo=bar"})
public class PropertyInjectionUnitTest {

    @Value("${foo}")
    private String foo;

    @Test
    public void whenPropertyProvided_thenProperlyInjected() {
        assertThat(foo).isEqualTo("bar");
    }
}

We can also achieve a similar effect using the properties argument of the @SpringBootTest annotation:

@RunWith(SpringRunner.class)
@SpringBootTest(
  properties = {"foo=bar"}, classes = SpringBootPropertiesTestApplication.class)
public class SpringBootPropertyInjectionIntegrationTest {

    @Value("${foo}")
    private String foo;

    @Test
    public void whenSpringBootPropertyProvided_thenProperlyInjected() {
        assertThat(foo).isEqualTo("bar");
    }
}

5.5. Hierarchical Properties

If we have properties that are grouped together, we can make use of the @ConfigurationProperties annotation, which will map these property hierarchies into Java objects graphs.

Let's take some properties used to configure a database connection:

database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar

And then let's use the annotation to map them to a database object:

@ConfigurationProperties(prefix = "database")
public class Database {
    String url;
    String username;
    String password;

    // standard getters and setters
}

Spring Boot applies it's convention over configuration approach again, automatically mapping between property names and their corresponding fields. All that we need to supply is the property prefix.

If you want to dig deeper into configuration properties, have a look at our in-depth article.

5.6. Alternative: YAML Files

Spring also supports YAML files.

All the same naming rules apply for test-specific, environment-specific, and default property files. The only difference is the file extension and a dependency on the SnakeYAML library being on our classpath.

YAML is particularly good for hierarchical property storage; the following property file:

database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar
secret: foo

is synonymous to the following YAML file:

database:
  url: jdbc:postgresql:/localhost:5432/instance
  username: foo
  password: bar
secret: foo

It's also worth mentioning that YAML files do not support the @PropertySource annotation, so if the use of the annotation was required, it would constrain us to using a properties file.

5.7. Properties From Command Line Arguments

Besides using files, we can pass properties directly on the command line:

java -jar app.jar --property="value"

We can also do this via system properties, which are provided before the -jar command rather than after it:

java -Dproperty.name="value" -jar app.jar

5.8. Properties From Environment Variables

Spring Boot will also detect environment variables, treating them as properties:

export name=value
java -jar app.jar

5.9. Randomization of Property Values

If we don't want determinist property values, we can use RandomValuePropertySource to randomize the values of properties:

random.number=${random.int}
random.long=${random.long}
random.uuid=${random.uuid}

5.10. Additional Types of Property Sources

Spring Boot supports a multitude of property sources, implementing a well-thought-out ordering to allow sensible overriding. It's worth consulting the official documentation, which goes further than the scope of this article.

6. Configuration Using Raw Beans in Spring 3.0 — the PropertyPlaceholderConfigurer

Besides the convenient methods of getting properties into Spring — annotations and the XML namespace — the property configuration bean can also be defined and registered manually.

Working with the PropertyPlaceholderConfigurer gives us full control over the configuration, with the downside of being more verbose and most of the time, unnecessary.

Let's see how we can define this bean using Java configuration:

@Bean
public static PropertyPlaceholderConfigurer properties() {
    PropertyPlaceholderConfigurer ppc
      = new PropertyPlaceholderConfigurer();
    Resource[] resources = new ClassPathResource[]
      { new ClassPathResource( "foo.properties" ) };
    ppc.setLocations( resources );
    ppc.setIgnoreUnresolvablePlaceholders( true );
    return ppc;
}

And using XML configuration:

<bean 
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:foo.properties</value>
        </list>
    </property>
    <property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>

7. Configuration Using Raw Beans in Spring 3.1 — the PropertySourcesPlaceholderConfigurer

Similarly, in Spring 3.1, the new PropertySourcesPlaceholderConfigurer can also be configured manually:

@Bean
public static PropertySourcesPlaceholderConfigurer properties(){
    PropertySourcesPlaceholderConfigurer pspc
      = new PropertySourcesPlaceholderConfigurer();
    Resource[] resources = new ClassPathResource[ ]
      { new ClassPathResource( "foo.properties" ) };
    pspc.setLocations( resources );
    pspc.setIgnoreUnresolvablePlaceholders( true );
    return pspc;
}

And the corresponding XML configuration:

<bean
  class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:foo.properties</value>
        </list>
    </property>
    <property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>

8. Properties in Parent-Child Contexts

This question comes up again and again: What happens when our web application has a parent and a child context? The parent context may have some common core functionality and beans, and then one (or multiple) child contexts, maybe containing servlet-specific beans.

In that case, what's the best way to define properties files and include them in these contexts? And how to best retrieve these properties from Spring?

We'll give a simple breakdown.

8.1. If the Properties File Is Defined in XML With <property-placeholder>

If the file is defined in the Parent context:

  • @Value works in Child context: NO
  • @Value works in Parent context: YES

If the file is defined in the Child context:

  • @Value works in Child context: YES
  • @Value works in Parent context: NO

Finally, as we discussed before, <property-placeholder> does not expose the properties to the environment, so:

  • environment.getProperty works in either context: NO

8.2. If the Properties File Is Defined in Java With @PropertySource

If the file is defined in the Parent context:

  • @Value works in Child context: YES
  • @Value works in Parent context: YES
  • environment.getProperty in Child context: YES
  • environment.getProperty in Parent context: YES

If the file is defined in the Child context:

  • @Value works in Child context: YES
  • @Value works in Parent context: NO
  • environment.getProperty in Child context: YES
  • environment.getProperty in Parent context: NO

9. Conclusion

This article showed several examples of working with properties and properties files in Spring.

As always, the entire code backing the article is available over on GitHub.

Spring bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
40 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Anup
Anup
6 years ago

What a post ..so very informative ..!!.However I wish to add a use case which probably your post does not adher to . Use case :- I have a use case where in I wish to read the values from the property files from my java code .Some way similiar to Env.getProperty.(). I cant use @Value which assigns a value to a variable bcoz the I have to read the value directly from the .property files [email protected] allows me to hardcode a key against a variable. In regards to env.getProperty() I am not sure whether Env.getProperty() allows us to add… Read more »

Eugen Paraschiv
6 years ago
Reply to  Anup

Hey Anup, thanks for the interesting usecase – I’ll take a look and get back to you.
Cheers,
Eugen.

Eugen Paraschiv
6 years ago
Reply to  Anup

Hey Anup – so let me see if I understand your usecase correctly. Are you’re trying to set values of these properties at runtime? Or are you just trying to read the properties from the file?
If you’re trying to set values of properties at runtime – what is the reason for that?
If you are just reading the properties – why do you need another mechanism (other than env.getProperty()?)
Cheers,

Eugen.

Anup
Anup
6 years ago

Hey Eugen, I wish to read the properties from file .However as mentioned in the previous post ,I cant use env.getProperty() because I wish to put dynamic data in the message that I read from the properties using placeholders. To adher to this use case I had to use org.springframework.context.support.ResourceBundleMessageSource which internally uses ResourceBundle which in turn allows us to insert Dynamic data in the messages against a particular key in properties file. For example in my property file i have this entry xyzKey= Welcome {0} to the site. So while reading it in my code I use the below… Read more »

Eugen Paraschiv
6 years ago
Reply to  Anup

I see – well, in that case, you can have a property with that value, but you will of course have no resolution of {0} = you’ll need to handle that yourself. If you also need resulution for the placeholder, then properties are not your best bet, as they are not meant to solve this kind of problem.
Properties are simple – they have clear purpose and do it well, but they do have their constraints and cannot be used for everything.
Hope this helps.
Cheers,
Eugen.

Boxing Cat
Boxing Cat
6 years ago

In 7.2 not

Eugen Paraschiv
6 years ago
Reply to  Boxing Cat

Nice catch – fixed. Thanks,
Eugen.

Tonio Caputo
Tonio Caputo
6 years ago

Nice article, all in one, thanks for it !!!! One thing its worth to mention, a use case I faced sometime ago not present in this article, how to use a ‘placeholder’ in an import statement, useful when the property value is not known at start time (if not you can just add it as a java property). Since spring 3.1 (as you probably already know) you can implement ApplicationContextInitializer and add properties (placeholders) you can use in your imports at runtime, may be its also useful in other use cases I can’t figure out right now. Hope this info… Read more »

Eugen Paraschiv
6 years ago
Reply to  Tonio Caputo

Hey Tonio – thanks for the suggestion – yes, I’ve been using that extensivelly and now I added it to the article as well. Cheers,
Eugen.

Duane
Duane
6 years ago

I can’t seem to download the Spring Properties Tutorial sample project. When I click on the link, it tells me I need to subscribe, but when I enter my email, it redirects me to a page that says I’m already subscribed, with no way I can see to download the sample project.

Eugen Paraschiv
6 years ago
Reply to  Duane

Hey Duane – if you’re already subscribed, that’s the way it should behave, yes. However, you should also receive the email with the download link, regardless of the fact that you’re subscribed. Hope that makes sense – and do let me know if that’s not the case. Cheers,
Eugen.

Jayakumar Jayaraman
Jayakumar Jayaraman
6 years ago

Very useful. Mainly ignore-unresolvable=”true” helped me when I had multiple files and struggled to fix a error due to this.

Comments are closed on this article!