How does @Value with a ${...} placeholder work, and how do you supply a default when the property is missing?
answer
- ${prop:default} = default when absent
- PropertySourcesPlaceholderConfigurer resolves it
- Missing + no default → Could not resolve placeholder
- String converted via ConversionService
- Not on static fields
basics
~10 s@Value("${my.prop}") injects the value of property my.prop from the environment into a field or parameter. Use ${my.prop:fallback} to supply a default when the property is not set.
solid answer
~40 s@Value("${prop}") tells Spring to resolve the placeholder ${prop} against the Environment (application.properties/yaml, env vars, system properties) and inject the resolved value into the annotated field, constructor param, or method arg. Resolution is done by a PropertySourcesPlaceholderConfigurer, which Spring Boot auto-registers. Syntax ${prop:default} supplies a default used only when the property is absent; ${prop:} yields an empty string. If a placeholder has no property and no default, Spring throws IllegalArgumentException: Could not resolve placeholder at startup. The injected text is converted to the target type (int, boolean, Duration, etc.) by the ConversionService. Prefer constructor injection so the field is final and validated at construction time.
code
java · 16 lines@Component
public class MailSettings {
private final String host;
private final int port;
private final boolean tls;
// Constructor injection: values resolved before the body runs
public MailSettings(
@Value("${mail.host}") String host, // required
@Value("${mail.port:25}") int port, // default 25, converted to int
@Value("${mail.tls:true}") boolean tls) { // default true, converted to boolean
this.host = host;
this.port = port;
this.tls = tls;
}
}go deeper
Know ${prop} injects a property and ${prop:default} adds a fallback.
Explain who resolves placeholders (PropertySourcesPlaceholderConfigurer), the fail-fast on missing property, and String→type conversion.
Contrast constructor vs field injection timing, empty-default semantics ${prop:}, and when to switch to @ConfigurationProperties.
Discuss configuration strategy: @Value for a few flags vs typed binding; startup validation; and the plain-Spring requirement to register the configurer as a static bean.
## What @Value does `@Value` is a Spring annotation that injects a computed value into a bean member. When its string starts with `${...}` it is a *property placeholder*: Spring looks up the named property in the `Environment` and substitutes the resolved value. ## Where properties come from The `Environment` aggregates ordered `PropertySource`s: - `application.properties`/`application.yml`, - OS environment variables, - JVM `-D` system properties, - command-line args, etc. (The exact ordering/precedence is a separate topic.) `@Value` only asks for the *final resolved* value. ## Who resolves placeholders A `PropertySourcesPlaceholderConfigurer` (a `BeanFactoryPostProcessor`) performs the `${...}` substitution on bean-definition values and `@Value` strings. In Spring Boot this bean is auto-registered; in plain Spring you must declare one (a `static @Bean` method) or placeholders won't be replaced and you'll see the literal `${...}` text. ## Defaults and missing properties **Defaults.** - `${prop:default}` uses `default` when `prop` is undefined. - `${prop:}` gives an empty string. - Defaults can themselves nest placeholders: `${prop:${fallback.prop}}`. **Missing property, no default.** Resolution fails fast: `IllegalArgumentException: Could not resolve placeholder 'prop' in value "${prop}"` during context startup. This is usually desirable — misconfiguration surfaces immediately. ## Type conversion The resolved value is always a String from the property source. Spring converts it to the target member type using the `ConversionService` (Boot's `ApplicationConversionService`) plus built-in `PropertyEditor`s: - `"8080"`→`int`, - `"true"`→`boolean`, - `"10s"`→`Duration`, - `"a,b,c"`→`List<String>`/`String[]`. ## Using it well **Where you can put it.** Fields, constructor parameters, `@Bean` method parameters, and setter/method parameters. It does **not** work on `static` fields. **When to use.** `@Value` is best for a small number of individual settings. For a group of related properties prefer `@ConfigurationProperties`, which binds a whole typed object, supports relaxed binding and validation, and is easier to test. **Gotcha.** Escaping: a literal `${` in a default needs care; and reading a `@Value` field inside the constructor of the *same* bean sees `null` for field injection because field injection happens after construction — use constructor-parameter `@Value` instead.
- What happens at startup if mail.host is not defined anywhere and has no default?Context startup fails with IllegalArgumentException: Could not resolve placeholder 'mail.host'. This is fail-fast behavior.
- Why prefer constructor @Value over field @Value?The value is available during construction (usable in the constructor body), the field can be final/immutable, and the class is easy to unit-test by passing values directly without Spring.
saying these in an interview costs you the question
- Saying ${prop} evaluates SpEL — it's placeholder resolution, not SpEL
- Thinking a missing property silently injects null instead of failing
- Claiming @Value works on static fields
- Believing you never need a PropertySourcesPlaceholderConfigurer even in plain (non-Boot) Spring