What is the Spring Expression Language (SpEL) and where do you commonly use it in a Spring application?
answer
- #{...} = SpEL, ${...} = placeholder
- @Value, @PreAuthorize, @Cacheable, @EventListener
- parse -> Expression -> getValue(context)
- @beanName references, T() types
- runtime, against an object graph
basics
~10 sSpEL is a small expression language that Spring evaluates at runtime. You write expressions inside #{...} — often in @Value — to compute values, call methods, read bean properties, or reference other beans.
solid answer
~40 sSpEL (Spring Expression Language) is a runtime expression language built into spring-core. It lets you embed dynamic expressions that Spring parses and evaluates against an object graph. The most visible use is @Value("#{...}") for injecting computed values, referencing other beans (@beanName.property), calling methods, or reading system properties. It also powers @PreAuthorize/@PostAuthorize security expressions, @Cacheable/@CacheEvict key/condition attributes, @EventListener(condition=...), @Scheduled(cron="#{...}"), and XML/bean definitions. Key syntax: literals, property access (obj.prop), method calls (obj.method()), T(java.lang.Math) to reach static members/types, the ternary/Elvis operators, and collection selection/projection. Under the hood a SpelExpressionParser produces an Expression that is evaluated against an EvaluationContext. Crucially, #{...} means a SpEL expression while ${...} is a property placeholder — different mechanisms.
code
java · 19 lines@Component
public class GreetingConfig {
// Literal computed value
@Value("#{'Hello ' + systemProperties['user.name']}")
private String greeting;
// Reference another bean's property by name
@Value("#{appProperties.maxUsers}")
private int maxUsers;
// Elvis operator: fall back if bean property is null
@Value("#{appProperties.region ?: 'us-east'}")
private String region;
// Static method via T()
@Value("#{T(java.lang.Runtime).getRuntime().availableProcessors()}")
private int cores;
}go deeper
Know that SpEL is a runtime expression language, used in @Value with #{...}, and can compute values or read other beans.
Distinguish #{} from ${}, list several annotations that accept SpEL, and show property access, method calls, and the Elvis operator.
Explain the parse->Expression->getValue(context) pipeline, the BeanExpressionResolver behind @Value, and when to prefer real Java/@ConfigurationProperties over SpEL.
Discuss testability/maintainability trade-offs, security exposure of SpEL, and set org-wide guidance on where SpEL is acceptable versus banned (e.g. never over user input).
## What SpEL is The **Spring Expression Language (SpEL)** is a lightweight, general-purpose expression language shipped in the `spring-core`/`spring-expression` module (`org.springframework.expression.*`). It is *not* tied to the ApplicationContext — you can use it standalone — but Spring wires it into many annotations so you can write dynamic, runtime-evaluated snippets in configuration. An **expression** is a string that, when *parsed* and *evaluated*, produces a value. Example: `"'Hello ' + name"` evaluated against an object that has a `name` property yields a greeting string. ## The `#{...}` vs `${...}` distinction (critical) - `#{ ... }` = a **SpEL expression** — Spring parses and evaluates the language inside. - `${ ... }` = a **property placeholder** — resolved by `PropertySourcesPlaceholderConfigurer` from the `Environment`/property sources. This is *not* SpEL; it is plain text substitution. They can be combined: `@Value("#{'${app.mode}' == 'fast'}")` first substitutes the placeholder `${app.mode}`, then SpEL evaluates the resulting boolean expression. (Placeholder binding itself is covered by sibling leaves; here we focus on the SpEL half.) ## Where SpEL is used - **`@Value("#{...}")`** — inject a computed value into a field/constructor parameter. - **Bean references** — `@Value("#{someBean.someProperty}")` reads a property off another Spring bean by name. - **Method Security** — `@PreAuthorize("hasRole('ADMIN') and #id == principal.id")`. - **Caching** — `@Cacheable(key = "#user.id", condition = "#user.active")`. - **`@EventListener(condition = "#event.important")`**. - **`@Scheduled`**, `@ConditionalOnExpression`, XML bean definitions, and more. ## Core syntax you should recognize - **Literals**: `'text'`, `42`, `3.14`, `true`, `null`. - **Property access**: `person.name`, nested `person.address.city`. - **Method invocation**: `person.getName()`, `'abc'.toUpperCase()`. - **Operators**: arithmetic (`+ - * / %`), relational (`==`, `!=`, `<`, `>`, `matches`), logical (`and`, `or`, `not`/`!`), ternary `a ? b : c`, and **Elvis** `a ?: b` (use `b` if `a` is null). - **Safe navigation**: `person?.name` returns `null` instead of throwing if `person` is null. - **`T(...)`**: `T(java.lang.Math).random()` accesses a **type**/its static members. - **Collection selection/projection**: `list.?[condition]` / `list.![expression]`. - **Variables**: `#root`, `#this`, and custom `#var`. ## How it works internally A `SpelExpressionParser` (implements `ExpressionParser`) turns the string into an `Expression`. Calling `expression.getValue(context, rootObject)` evaluates it against an `EvaluationContext`, which holds the root object, variables, functions, property accessors, and type resolvers. When Spring resolves `@Value`, it uses a `BeanExpressionResolver` (`StandardBeanExpressionResolver`) with a context whose root/bean-reference resolution is wired to the `BeanFactory`, which is why `@beanName` works. ## Gotchas - Forgetting `#{...}` — a bare string in `@Value` with no `#{}`/`${}` is injected literally. - Mixing up `#{}` (SpEL) and `${}` (placeholder). - Property access is **case-sensitive** and uses JavaBean getters. - SpEL over untrusted input is dangerous (see the security question in this leaf). ## When to use it Use SpEL for small, declarative dynamic wiring (compute a value, reference another bean, guard a cache key). For anything complex, prefer real Java code in a `@Bean` method or a `@ConfigurationProperties` object — SpEL is hard to test and debug.
- What is the difference between #{...} and ${...} in a @Value?#{...} is a SpEL expression that Spring parses and evaluates at runtime; ${...} is a property placeholder resolved from the Environment/property sources as plain text substitution. They are different mechanisms and can be nested, e.g. #{ '${...}' ... }.
- Is SpEL only usable through @Value?No. It is also used in @PreAuthorize/@PostAuthorize, @Cacheable/@CacheEvict key and condition attributes, @EventListener(condition=...), @ConditionalOnExpression, @Scheduled cron via #{...}, and XML bean definitions. You can also use SpelExpressionParser programmatically with no ApplicationContext at all.
saying these in an interview costs you the question
- Claiming #{...} and ${...} are the same thing
- Saying SpEL is evaluated at compile time (it is runtime)
- Thinking SpEL requires an ApplicationContext to work at all
- Believing a bare @Value string is treated as SpEL without #{}