What is Spring's Environment / PropertySources abstraction, and what does @PropertySource do?
answer
- Environment → MutablePropertySources → ordered list
- first match wins (earlier = higher precedence)
- systemProperties before systemEnvironment
- @PropertySource loads .properties, not YAML
- ignoreResourceNotFound / encoding / factory attributes
basics
~20 sThe 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 sSpring'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@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
Know that Environment stores an ordered list of property sources and @PropertySource loads a .properties file into it.
Add the default ordering (system props → env vars → @PropertySource files) and first-match-wins semantics, plus the YAML/ignoreResourceNotFound caveats.
Discuss the concrete PropertySource types, that @PropertySource is processed during config-class parsing, and how it interacts with Boot's ConfigData loading.
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