skip to content

PropertySources & @PropertySource

Configuration is a stack of ordered PropertySources, and that order decides which value wins when the same key appears in a file, an environment variable and a system property. Precedence questions come up constantly, because overrides are how deployments are configured.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is Spring's Environment / PropertySources abstraction, and what does @PropertySource do?

level: juniorimportance: must knowfreq 58%

answer

  1. Environment → MutablePropertySources → ordered list
  2. first match wins (earlier = higher precedence)
  3. systemProperties before systemEnvironment
  4. @PropertySource loads .properties, not YAML
  5. ignoreResourceNotFound / encoding / factory attributes

basics

~20 s

The Environment holds an ordered list of PropertySources (files, JVM system properties, OS env vars). getProperty() searches them in order. @PropertySource loads a .properties file and adds it as one more source so its keys become available.

solid answer

~40 s

Spring's Environment is the runtime abstraction over configuration. It wraps a MutablePropertySources — an ordered collection of named PropertySource objects, each a key→value lookup (a .properties file, the JVM's system properties, OS environment variables, a Map, etc.). environment.getProperty("x") walks the sources in order and returns the first match. @PropertySource is a class-level annotation on a @Configuration class that loads a classpath/file .properties resource and registers it as an additional PropertySource in that Environment, so its keys can be read via getProperty or resolved in ${...} placeholders. It supports ignoreResourceNotFound and encoding attributes, and placeholders in its own location value. Note it does not load YAML by default.

code

java · 18 lines
java
@Configuration
@PropertySource(value = "classpath:app.properties", ignoreResourceNotFound = true, encoding = "UTF-8")
public class AppConfig {

    private final Environment env;

    public AppConfig(Environment env) {
        this.env = env;
    }

    @PostConstruct
    void show() {
        // walks the ordered PropertySources, first match wins
        String url = env.getProperty("db.url");
        String missing = env.getProperty("nope", "fallback");
        System.out.println(url + " / " + missing);
    }
}

go deeper

for a junior

Know that Environment stores an ordered list of property sources and @PropertySource loads a .properties file into it.

for a middle

Add the default ordering (system props → env vars → @PropertySource files) and first-match-wins semantics, plus the YAML/ignoreResourceNotFound caveats.

for a senior

Discuss the concrete PropertySource types, that @PropertySource is processed during config-class parsing, and how it interacts with Boot's ConfigData loading.

for a principal

Frame it as a layered override strategy for ops, and know when NOT to use @PropertySource (prefer Boot ConfigData / profile-specific files / externalized config).

## The Environment Every Spring `ApplicationContext` owns a `ConfigurableEnvironment` (default `StandardEnvironment`). It has two jobs: **profiles** and **properties**. For properties it exposes: - `getProperty(name)`, `getRequiredProperty`, `containsProperty`, - and — via the `ConfigurableEnvironment` sub-interface — `getPropertySources()` returning a `MutablePropertySources`. ## PropertySource A `PropertySource<T>` is an abstract, *named* key→value source: `getName()`, `containsProperty(name)`, `getProperty(name)`. Concrete types include: - `MapPropertySource`, - `PropertiesPropertySource`, - `ResourcePropertySource` (loads a `.properties` file), - `SystemEnvironmentPropertySource` (OS env, with relaxed name matching), - and `CommandLinePropertySource`. ## MutablePropertySources = ordered list It is an ordered collection. `getProperty` iterates from **first to last** and returns the **first** source that contains the key — so *earlier = higher precedence*. `StandardEnvironment` pre-registers two sources: 1. `systemProperties` (from `System.getProperties()`, i.e. JVM `-Dx=y`) placed **before** 2. `systemEnvironment` (from `System.getenv()`, OS variables). So a JVM `-D` flag beats an OS env var of the same name. ## @PropertySource A class-level annotation (repeatable; container is `@PropertySources`) on a `@Configuration` class. Its `value` names a resource location, e.g. `@PropertySource("classpath:app.properties")`. During configuration-class parsing (`ConfigurationClassPostProcessor`), Spring loads the resource into a `ResourcePropertySource` and adds it to the Environment. Attributes: - `name` (override the source name), - `ignoreResourceNotFound=true` (don't fail if the file is missing), - `encoding="UTF-8"`, - and `factory` (a custom `PropertySourceFactory`, needed because the default only reads `.properties`/`.xml`, **not YAML**). ## Where the loaded keys sit By default `@PropertySource` files are added **below** system properties and OS env vars, so those can override file values — this is deliberate so ops can override packaged defaults at runtime. ## When to use `@PropertySource` is the classic plain-Spring way to load an external properties file into the Environment. In **Spring Boot** you usually don't need it: Boot loads `application.properties`/`application.yml` through its own `ConfigData` machinery (not `@PropertySource`), and Boot also supports YAML there. Reach for `@PropertySource` in non-Boot apps or to pull in an *extra* legacy `.properties` file.

  • If the same key exists in app.properties and as an OS environment variable, which wins by default?
    The OS environment variable. @PropertySource files are registered below the systemEnvironment source, so environment variables (and JVM system properties) override packaged file defaults.
  • Can @PropertySource load a YAML file?
    Not with the default factory — it only understands .properties (and .xml). You must supply a custom PropertySourceFactory (e.g. wrapping YamlPropertiesFactoryBean). Spring Boot's application.yml is loaded by a different mechanism, not @PropertySource.

saying these in an interview costs you the question

  • Thinking @PropertySource values automatically override system properties / env vars
  • Claiming @PropertySource can load YAML out of the box
  • Confusing @PropertySource with Boot's application.properties loading (different mechanism)
  • Saying property sources are unordered / that last one wins by default

context

open as a page

In the default StandardEnvironment, what is the precedence order between JVM system properties, OS environment variables, and an @PropertySource file — and why?

level: middleimportance: must knowfreq 60%

basics

~10 s

JVM system properties (-D) win over OS environment variables, which win over @PropertySource files. Lookup walks the ordered list and takes the first match, and @PropertySource files are added at the bottom.

open as a page

How does ${...} placeholder resolution work against the PropertySources, and what role does PropertySourcesPlaceholderConfigurer play?

level: middleimportance: must knowfreq 52%

basics

~10 s

${key} placeholders are resolved by looking key up in the Environment's ordered PropertySources. ${key:default} supplies a fallback. In plain Spring, a PropertySourcesPlaceholderConfigurer bean resolves these placeholders; Spring Boot registers one automatically.

open as a page

How do you programmatically add or reorder PropertySources via MutablePropertySources, and at what point in the lifecycle should you do it?

level: seniorimportance: should knowfreq 33%

basics

~10 s

Get ConfigurableEnvironment.getPropertySources() (a MutablePropertySources) and use addFirst/addLast/addBefore/addAfter/replace/remove to control ordering. Do it early — in an ApplicationContextInitializer or EnvironmentPostProcessor — before beans read properties.

open as a page

Explain SystemEnvironmentPropertySource's relaxed name matching and the subtler @PropertySource gotchas (YAML, location placeholders, repeatable ordering, profiles).

level: principalimportance: nice to knowfreq 18%

basics

~10 s

SystemEnvironmentPropertySource matches names leniently: env.getProperty("db.url") also finds DB_URL (dots↔underscores, case-insensitive). @PropertySource gotchas: no YAML by default, its location placeholder can't self-reference, later declarations override earlier ones, and it isn't profile-aware like Boot's config files.

open as a page