If you are a Spring developer and and you have created a Java based container configuration, you have probably come across the @PropertySource annotation for importing resources. It was first added as part of Spring 3.1, but Spring 4 has added some welcome improvements.

Basics

Let’s start with a simple example:

@Configuration
@PropertySource(value = "classpath:application.properties")
public class ApplicationConfig {

    // more configuration ...
}

When executed, properties will be imported from the application.properties file, located in the classpath root. classpath is the default location, and can thus be omitted:

@Configuration
@PropertySource("application.properties")
public class ApplicationConfig {
}

Alternatively, it is possible to specify a file: location to appoint a properties file that is located elsewhere on your host environment:

@PropertySource("file:/path/to/application.properties")

Other possible resource strings include http: and ftp:, please see the Resource chapter in the Spring reference documentation for details.

Multiple Properties Files

It is also possible to specify two or more files:

@PropertySource({"default.properties", "overriding.properties"})

Note that the order of the declared files is important. If the same key is defined in two or more files, the value associated with the key in the last declared file will override any previous value(s).

${…} Placeholders

In the @PropertySource JavaDoc it is stated that:

Any ${…} placeholders present in a @PropertySource resource location will be resolved against the set of property sources already registered against the environment.

Thus, it is possible to specify a system property or an environment variable that will be resolved to its actual value when your application starts. For example, ${CONF_DIR} below will be replaced with its associated value when the Spring application starts:

@PropertySource("file:${CONF_DIR}/application.properties")
$ echo $CONF_DIR
/path/to/directory/with/app/config/files

Of course, you can let the file name be included in the environment variable:

@PropertySource("file:${APP_PROPERTIES}")
$ echo $APP_PROPERTIES
/path/to/application.properties

This approach can be very useful if your application needs different properties in different environments, such as client vs. server deployment, Linux vs. Windows target operating system and so on.

Spring 4

Spring 4 brings two new features to the @PropertySource. The first new feature deals with missing files. By default, Spring will throw an exception if it does not find the file that has been declared. Given a project that does not contain a missing.properties file, but has the following declaration:

@PropertySource(value = "missing.properties")

If one attempts to start the application anyway, there will be a stacktrace accordingly:

java.lang.IllegalStateException: Failed to load ApplicationContext
[...]
Caused by: java.io.FileNotFoundException: class path resource [missing.properties] cannot be opened because it does not exist

To overcome this problem, the ignoreResourceNotFound attribute has been added to the @ProperySource annotation. Consequently, the declaration:

@PropertySource(value = "missing.properties", ignoreResourceNotFound = true)

will cause Spring to silently ignore that the missing.properties file cannot be found. This may seem odd at first, if one does not care about the absent file, then why bother to declare it the first place? As will be explained later, there is a very good reason for this. Secondly, there is a new annotation called @PropertySources that allows you to declare repeated @PropertySource annotations:

@PropertySources({
    @PropertySource("default.properties"),
    @PropertySource("overriding.properties")
})

Yet again, the order of the property file declarations is important. As suggested by the file names in the example above, files declared later will override any previous value(s) if they contain the same key(s).

Putting It Together

To summarize, a property source configuration can be implemented like:

@Configuration
@PropertySources({
    @PropertySource("default.properties"),
    @PropertySource(value = "file:${CONF_DIR}/optional-override.properties", ignoreResourceNotFound = true)
}
public class ApplicationConfig {
}

The default.properties file is part of the project jar or war file, and consequently availible on the classpath. However, now we can see that the addition of the ignoreResourcesNotFound attribute allow us to optionally override one or more of the properties depending on the deployment environment. Additionally, the use of file and the ${...} placeholder enable a configurable location of this optional properties file. For the record, it is possible to conditionally import properties files in earlier Spring versions as well using placeholders and :, but then it was an either / or inclusion on file level. Prior to Spring 4, you were forced to copy all properties to the overriding file even if you only had the need of overriding a single property value. See the JavaDoc for details.

Java 8

When you migrate update to Java 8, the @PropertySources annotation will be redundant, because Java 8 will support repeating annotations:

@Configuration
@PropertySource("default.properties")
@PropertySource(value = "file:${CONF_DIR}/optional-override.properties", ignoreResourceNotFound = true)
public class ApplicationConfig {
}

Edit

In the earlier version of Spring 4, i.e. versions below 4.0.2, an exception will be thrown if a placeholder such as the ${CONF_DIR} above cannot be resolved, despite that ignoreResourceNotFound attribute has been set to true. SPR-11524 addresses this issue, and a solution is scheduled to be released as part of the 4.0.3 version.

References

Updated: