We are still cooking the magic in the way!
@Value & the Spring Expression Language (SpEL)
@Value & the Spring Expression Language (SpEL)
Properties files and environment variables store your application's external configuration: database URLs, timeout values, feature flags, and dozens of other settings that differ between development, staging, and production. @Value is the primary annotation Spring uses to inject those external values directly into your beans. On top of that, Spring ships a small but powerful expression engine — the Spring Expression Language (SpEL) — that lets you compute values at injection time rather than just copying a raw string.
Basic @Value Injection
The simplest form of @Value pulls a property from application.properties (or application.yml) using a property placeholder delimited by ${...}.
Spring performs type conversion automatically: the String value "3" in the properties file becomes an int, "5000" becomes a long, and "false" becomes a boolean. This works for all primitive types, their wrappers, and a number of common value types.
Default Values
If a property is missing and no default is provided, Spring throws a BeanCreationException at startup — fast fail, not a silent null. You can supply a fallback using the colon syntax inside the placeholder:
Injecting Lists and Arrays
A comma-separated property value can be injected directly into an array or List:
ConversionService. It applies to arrays and List<T> where T is a type Spring can convert a single string to. For complex structures (maps, nested objects) prefer @ConfigurationProperties over @Value.
Introduction to SpEL — #{...}
When you need more than a raw property value, you can embed a SpEL expression inside #{...}. SpEL is evaluated at runtime by the Spring container and can reference other beans, call methods, do arithmetic, and access system properties.
Referencing Other Beans in SpEL
SpEL can reach into other Spring-managed beans by name, calling methods or reading properties:
The bean name in SpEL defaults to the simple class name with a lowercase first letter unless you specify a name explicitly with @Component("appConfig").
Mixing ${...} and #{...}
You can nest property placeholders inside SpEL expressions to combine externalized configuration with runtime computation:
@Value expression is longer than a single line or requires multiple conditions, that logic belongs in a @PostConstruct method or a dedicated configuration class, not in an annotation. Complex SpEL expressions are hard to test, impossible to type-check at compile time, and difficult to debug.
System Properties and Environment Variables
SpEL exposes two implicit objects: systemProperties (JVM system properties from -D flags) and systemEnvironment (OS environment variables). You can access either directly:
In Spring Boot it is almost always simpler to use ${MY_ENV_VAR} (property placeholder) because Boot already maps environment variables into its Environment abstraction. Reserve the SpEL systemEnvironment syntax for cases where you need to combine it with other SpEL operations.
Constructor and Method Parameter Injection
@Value is not limited to fields. You can annotate constructor parameters and method parameters, which makes the bean easier to unit-test without a Spring context:
With constructor injection you can simply new PaymentService("test-key", 500) in a unit test — no application context needed, no reflection magic, no mocking framework required for the configuration itself.
@Value vs @ConfigurationProperties
Knowing when to use each avoids a common architectural smell:
- @Value — one or two scattered properties that belong to different prefixes; quick access to computed or environment values via SpEL; places where a strongly-typed binding class would be overkill.
- @ConfigurationProperties — a cohesive group of related properties sharing a common prefix (e.g.,
app.mail.*). Gives you a typed POJO, IDE auto-completion, JSR-303 validation on startup, and better testability.
@Value as the exception, not the rule. For any feature that has more than two or three configuration knobs, create a @ConfigurationProperties record or class. Reserve @Value for single-property injection and SpEL for the cases where you need runtime computation.
Summary
@Value("${property}") injects externalized configuration into beans with automatic type conversion and optional defaults. @Value("#{expression}") embeds a SpEL expression evaluated at container startup, giving you access to other beans, arithmetic, conditionals, and system properties. The two syntaxes compose: you can nest ${} placeholders inside #{} expressions. Prefer constructor-parameter injection over field injection for testability, and migrate to @ConfigurationProperties whenever a group of related properties grows beyond a handful of values.