skip to content

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