How to Use @PropertySource in Your Spring Application

What is the @PropertySource annotation?

The @PropertySource annotation is used to tell Spring to load a specific properties file from a location provided in the annotation. It is used in conjunction with @Configuration at the class level. It allows you, as a developer, to externalize the configuration of your application.

Why use @PropertySource?

  1. It allows you to load properties files from any location.
  2. In Java 8+, you can repeat this annotation many times, allowing you to load multiple configuration files.
  3. It supports the usage of placeholders using Spring Expression Language syntax.
  4. You can handle missing files by ignoring them if they are not found.
  5. Property override: if you have many properties with the same name, the last definition will override the first one.

How to use @PropertySource

The first example is the default way, by configuring with @Configuration and pointing to a path:

@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig {

    private static final Logger logger = getLogger(AppConfig.class);
    @Value("${property.name}")
    private String propertyName;

    @PostConstruct
    public void init() {
        logger.info("Property loaded: property.name={}", propertyName);
    }
    // getters and setters
}

Here’s the configuration file:

property.name=property value

If you run the example above the init() will show the value of the property in the console:

INFO 17840 --- [           main] org.spring.mastery.config.AppConfig      : Property loaded: property.name=property value

You can define as many @PropertySource annotations as you want:

@Configuration
@PropertySource("classpath:application.properties")
@PropertySource("classpath:another.properties")
public class AppConfig {

    private static final Logger logger = getLogger(AppConfig.class);
    @Value("${property.name}")
    private String propertyName;

    @Value("${another.property}")
    private String anotherProperty;

    @PostConstruct
    public void init() {
        logger.info("Property loaded: property.name={}", propertyName);
        logger.info("Property loaded: property.name={}", anotherProperty);
    }
    // getters and setters
}

The console will have these lines:

INFO 28208 --- [           main] org.spring.mastery.config.AppConfig      : Property loaded: property.name=property value
INFO 28208 --- [           main] org.spring.mastery.config.AppConfig      : Property loaded: property.name=another valu

You can use @PropertySources to group them if you want:

@Configuration
@PropertySources({
    @PropertySource("classpath:application.properties"),
    @PropertySource("classpath:another.properties")
})
public class AppConfig {
    @Value("${property.name}")
    private String propertyName;

    @Value("${another.property}")
    private String anotherProperty;

    // getters and setters
}

It’ll work like the previous example:

INFO 28316 --- [           main] org.spring.mastery.config.AppConfig      : Property loaded: property.name=property value
INFO 28316 --- [           main] org.spring.mastery.config.AppConfig      : Property loaded: property.name=another value

You can use a placeholder using Spring Expression Language to make things more flexible by using one property to define a path location to another property file. You can use this in scenarios where you can add a .properties file that will be placed outside your project (in this example is still in the class path, but you can put it where you want in the file system. This is useful in production systems where you want to hide the properties that will be used in the production server from the source code.

@Configuration
@PropertySource("classpath:${config.location}/external.properties")
public class AppConfig {

    private static final Logger logger = getLogger(AppConfig.class);
    @Value("${external.property.name}")
    private String propertyName;

    @PostConstruct
    public void init() {
        logger.info("Property loaded: property.name={}", propertyName);
    }
    // getters and setters
}

The application.properties will look like this:

property.name=property value
config.location=external

And the external.properties will look like this:

external.property.name=external value

PS: The external name is optional; you can add the name you want.

You can also ignore the property loading if the file is not found:

@Configuration
@PropertySource(value = "classpath:optional.properties", ignoreResourceNotFound = true)
public class AppConfig {

    private static final Logger logger = getLogger(AppConfig.class);
    @Value("${optional.property:default}")
    private String optionalProperty;

    @PostConstruct
    public void init() {
        logger.info("Property loaded: property.name={}", optionalProperty);
    }
    // getters and setters
}

If the optional.properties does not exist, the default value will be set:

INFO 8912 --- [           main] org.spring.mastery.config.AppConfig      : Property loaded: property.name=default

If it exists, it will show the property value defined on the existing optional.properites

INFO 29992 --- [           main] org.spring.mastery.config.AppConfig      : Property loaded: property.name=optional value

In this post, we learned different ways to use the @PropertySource in your project. Have you seen another way to use it? Did this annotation help you solve a problem in your project?

If you like this topic, make sure to follow me. In the following days, I’ll be explaining more about Spring annotations! Stay tuned!

Willian Moya (@WillianFMoya) / X (twitter.com)

Willian Ferreira Moya | LinkedIn


Posted

in

,

by