skip to content

Spring Expression Language (SpEL)

Spring's expression language evaluates property paths, method calls, collection projection and selection, and type references at runtime, inside @Value and many other annotations. Worth knowing precisely, because a SpEL expression built from user input is an injection risk.

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

questions

5

What is the Spring Expression Language (SpEL) and where do you commonly use it in a Spring application?

level: juniorimportance: must knowfreq 70%

answer

  1. #{...} = SpEL, ${...} = placeholder
  2. @Value, @PreAuthorize, @Cacheable, @EventListener
  3. parse -> Expression -> getValue(context)
  4. @beanName references, T() types
  5. runtime, against an object graph

basics

~10 s

SpEL 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 s

SpEL (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
java
@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

for a junior

Know that SpEL is a runtime expression language, used in @Value with #{...}, and can compute values or read other beans.

for a middle

Distinguish #{} from ${}, list several annotations that accept SpEL, and show property access, method calls, and the Elvis operator.

for a senior

Explain the parse->Expression->getValue(context) pipeline, the BeanExpressionResolver behind @Value, and when to prefer real Java/@ConfigurationProperties over SpEL.

for a principal

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 #{}

context

open as a page

Explain SpEL collection selection and projection. What do the .?[] and .![] operators do?

level: middleimportance: should knowfreq 45%

basics

~10 s

Selection .?[expr] filters a collection, keeping elements where the boolean expr is true. Projection .![expr] transforms each element, producing a new collection of the results. Inside both, #this is the current element.

open as a page

In SpEL, how do you access static members/types with T(), and how do you reference other Spring beans by name?

level: middleimportance: should knowfreq 35%

basics

~10 s

T(fully.qualified.Type) gives you a type reference so you can call its static methods, read static fields, or use enum constants — e.g. T(java.lang.Math).PI. To use another bean, write @beanName in the expression, e.g. @configService.timeout.

open as a page

How do you use SpEL programmatically? Walk through SpelExpressionParser and EvaluationContext, including #root and #this.

level: seniorimportance: should knowfreq 40%

basics

~20 s

Create a SpelExpressionParser, call parseExpression(str) to get an Expression, then getValue(). To evaluate against data and variables you pass an EvaluationContext (e.g. StandardEvaluationContext) holding a root object and #variables. #root is the root object; #this is the current item during iteration.

open as a page

Why is SpEL a security concern, and how do you evaluate potentially untrusted expressions safely?

level: principalimportance: should knowfreq 30%

basics

~20 s

A full SpEL context can call any static method or constructor via T(), so evaluating attacker-controlled expressions enables remote code execution (e.g. T(Runtime).exec). Never build expressions from user input; if you must evaluate dynamic strings, use SimpleEvaluationContext, which disables T(), constructors, and bean access.

open as a page