Backend Development 9 min read

Spring Expression Language (SpEL) Overview and Practical Usage

This article introduces Spring Expression Language (SpEL), explains its common syntax, demonstrates quick-start examples, shows real-world usage with AOP monitoring, and outlines its internal implementation, providing a concise guide for backend developers working with Spring.

Zhuanzhuan Tech
Zhuanzhuan Tech
Zhuanzhuan Tech
Spring Expression Language (SpEL) Overview and Practical Usage

Introduction

Spring Expression Language (SpEL) is a powerful expression language that supports runtime querying and manipulation of object graphs. It is part of Spring's core container alongside Beans, Core, and Context modules, and can be used with XML or annotation‑based configurations.

Common SpEL Usage

SpEL syntax resembles JSP EL and uses #{…} as delimiters. Supported expressions include literals (integers, decimals, scientific notation, strings, booleans), bean/property/method references, static method/field access, and various operators (arithmetic, comparison, logical, ternary, Elvis, regular expressions).

Quick Start

Simple examples demonstrate how to evaluate literal strings, invoke methods, and work with object properties using SpelExpressionParser and Expression objects.

public void demo() {
    // 1 Define parser
    SpelExpressionParser parser = new SpelExpressionParser();
    // 2 Parse expression
    Expression exp = parser.parseExpression("'xxx'");
    // 3 Get result
    String value = (String) exp.getValue();
    System.out.println(value); // xxx
}
public void demo() {
    // 1 Define parser
    SpelExpressionParser parser = new SpelExpressionParser();
    // 2 Parse expression
    Expression exp = parser.parseExpression("'xxx'.concat('yyy')");
    String value = (String) exp.getValue();
    System.out.println(value); // xxxyyy
    exp = parser.parseExpression("'xxx'.bytes");
    byte[] bytes = (byte[]) exp.getValue();
    exp = parser.parseExpression("'xxx'.bytes.length");
    int length = (Integer) exp.getValue();
    System.out.println("length: " + length); // length: 3
}
public void demo() {
    User user = new User();
    user.setName("xxx");
    User user2 = new User();
    user2.setName(user.getName());
    // 1 Define parser
    ExpressionParser parser = new SpelExpressionParser();
    // Specify expression
    Expression exp = parser.parseExpression("name");
    // 2 Get property value
    String name = (String) exp.getValue(user2);
    System.out.println(name); // xxx
    // 2.1 Evaluate expression
    Expression exp2 = parser.parseExpression("name == 'xxx'");
    boolean result = exp2.getValue(user2, Boolean.class);
    System.out.println(result); // true
}

Real‑world Application

In practice, SpEL is often used to evaluate object properties within AOP‑based monitoring. An example shows a custom @Monitor annotation that captures method parameters via SpEL, builds a monitoring key, and asynchronously sends alert information.

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Monitor {
    MonitorScenesTypeEnum scenes() default MonitorScenesTypeEnum.DEFAULT;
    String monitorSpEL() default "";
}
public void process(Monitor monitor, JoinPoint joinPoint, Object result, Throwable ex) throws ClassNotFoundException {
    MonitorScenesTypeEnum scenes = monitor.scenes();
    Integer code = scenes.getCode();
    // Get Apollo config
    Map
monitorConfigMap = apolloConfigService.getMonitorConfigMap();
    if (MapUtils.isEmpty(monitorConfigMap) || !monitorConfigMap.containsKey(code)) {
        return;
    }
    MonitorConfig monitorConfig = monitorConfigMap.get(code);
    // Validate result if needed
    String resultType = monitorConfig.getResultType();
    if (checkResult(result, resultType)) {
        return;
    }
    // Parse SpEL expression from annotation
    String monitorSpEL = monitor.monitorSpEL();
    String monitorTrace = StringUtils.isNotBlank(monitorSpEL) ?
        SpelParseUtil.generateKeyBySpEL(monitorSpEL, joinPoint) : StringUtils.EMPTY_STRING;
    // Capture exception info
    String otherParamsJson = "";
    if (Objects.nonNull(ex)) {
        Map
otherParams = Maps.newHashMap();
        String stackTraceAsString = Throwables.getStackTraceAsString(ex);
        String errMsg = stackTraceAsString;
        if (stackTraceAsString.length() > NumberConstant.NUMBER_512) {
            errMsg = stackTraceAsString.substring(0, NumberConstant.NUMBER_512) + "...";
        }
        otherParams.put("异常信息", errMsg);
        otherParamsJson = JsonUtil.silentObject2String(otherParams);
    }
    // Asynchronously send alert
    asyncSendMonitor(scenes, monitorTrace, otherParamsJson);
}
private static SpelExpressionParser parser = new SpelExpressionParser();
private static DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();

public static String generateKeyBySpEL(String spelString, JoinPoint joinPoint) {
    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    Method method = methodSignature.getMethod();
    String[] paramNames = nameDiscoverer.getParameterNames(method);
    Expression expression = parser.parseExpression(spelString);
    EvaluationContext context = new StandardEvaluationContext();
    Object[] args = joinPoint.getArgs();
    for (int i = 0; i < args.length; i++) {
        context.setVariable(paramNames[i], args[i]);
    }
    return Objects.requireNonNull(expression.getValue(context)).toString();
}
@Monitor(scenes = MonitorScenesTypeEnum.CHANGE_PRICE_FAIL, spelStr = "#request?.orderId")
public ChangePriceResponse changePrice(ChangePriceRequest request) {
    BizOrderContext
bizOrderContext =
        BizOrderContext.create(OrderEventEnum.C1_CHANGE_JM_PRICE, request);
    ZzAssert.isTrue(stateMachine.isCanFire(bizOrderContext), BizErrorCode.ORDER_STATUS_CHANGED);
    stateMachine.fire(bizOrderContext);
    return bizOrderContext.getResponse();
}

Simple Overview of SpEL Internal Implementation

SpEL parsing starts with ExpressionParser#parseExpression , which performs lexical analysis to split the expression into tokens, builds an abstract syntax tree (AST) using SpelNode , wraps it into an Expression , and later evaluates it against an EvaluationContext when Expression#getValue is called.

Conclusion

SpEL is widely used in Spring applications for dynamic expression evaluation, including monitoring, dynamic index creation, lock handling, caching, and within annotations such as @Cacheable , @Value , and Spring Security's @PreAuthorize family.

JavaAOPSpringSPELExpression Language
Zhuanzhuan Tech
Written by

Zhuanzhuan Tech

A platform for Zhuanzhuan R&D and industry peers to learn and exchange technology, regularly sharing frontline experience and cutting‑edge topics. We welcome practical discussions and sharing; contact waterystone with any questions.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.