Master Spring Expression Language (SpEL) in Spring Boot 3: Real-World Cases

This article introduces Spring Expression Language (SpEL) for Spring Boot 3, explains its core features such as collection filtering, projection, Elvis and safe navigation operators, method and bean references, regular‑expression handling, and arithmetic expressions, and provides complete runnable code examples demonstrating each technique.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Spring Expression Language (SpEL) in Spring Boot 3: Real-World Cases

Spring Expression Language (SpEL) is a powerful expression language provided by the Spring framework that enables runtime querying and manipulation of object graphs. It is widely used for configuration injection, conditional evaluation, security control, and more, allowing developers to write concise expressions directly in annotations or XML.

2.1 Collection Filtering and Projection

SpEL offers collection operations using .?[condition] for filtering and .![property] for projection.

public class Employee {
  private String name;
  private Integer age;
  private double salary;
  private String job;
}

@Configuration
public class EmployeeConfig {
  @Bean
  List<Employee> employees() {
    return List.of(
      new Employee("张伟", 28, 8500.0, "软件工程师"),
      new Employee("王芳", 34, 12000.5, "项目经理"),
      new Employee("李强", 25, 7200.0, "前端开发"),
      new Employee("刘敏", 31, 9500.75, "数据分析师"),
      new Employee("陈磊", 29, 8800.0, "后端开发"),
      new Employee("杨洋", 26, 7600.0, "UI设计师"),
      new Employee("黄娟", 33, 11000.0, "产品经理"),
      new Employee("周杰", 30, 9000.25, "系统架构师"),
      new Employee("吴婷", 27, 7800.0, "测试工程师"),
      new Employee("徐浩", 35, 13500.0, "技术总监")
    );
  }
}

@Component
public class EmployeeRunner implements CommandLineRunner {
  @Value("#{employees.?[salary > 9000].![name]}")
  private List<String> highPaidEmployeeNames;

  @Value("#{employees.?[age > 30 and salary < 60000]}")
  private List<Employee> middleAgedLowPaidEmployees;

  @Override
  public void run(String... args) throws Exception {
    highPaidEmployeeNames.forEach(System.err::println);
    middleAgedLowPaidEmployees.forEach(System.out::println);
  }
}

Result:

2.2 Elvis Operator and Safe Navigation

The Elvis operator ( ?:) and safe navigation operator ( ?.) help handle null values gracefully.

@Component
public class EmployeeRunner implements CommandLineRunner {
  @Value("#{systemProperties['pack.app.secret'] ?: 'xxxooo'}")
  private String appSecret;

  @Value("#{systemProperties['java.home'] ?: '/opt/'}")
  private String javaHome;

  @Override
  public void run(String... args) throws Exception {
    System.err.println(appSecret);
    System.err.println(javaHome);
  }
}

Output:

xxxooo
D:\devsoft\jdk-21_windows-x64_bin\jdk-21.0.1

Safe navigation example with nested objects:

public class Employee {
  private Address address;
}

public class Address {
  private String province;
  private String city;
  private String county;
}

@Service
public class EmployeeService {
  public Employee queryById() {
    return new Employee("Pack_xg", 23, 30000, "程序员", new Address("新疆", "乌鲁木齐", null));
  }
}

@Component
public class CountyRunner implements CommandLineRunner {
  @Value("#{@employeeService.queryById()?.address?.county ?: '未知区县'}")
  private String employeeCounty;

  @Override
  public void run(String... args) throws Exception {
    System.out.println(employeeCounty);
  }
}

Result:

未知区县

2.3 Method Invocation & Bean Reference

SpEL can invoke methods and reference Spring beans directly.

@Component("messageFormatter")
public class MessageFormatterComponent {
  public String format(String msg) { return msg; }
}

@Service
public class UserService {
  public User getCurrentUser() { return new User("Pack_xg"); }
  public static record User(String name) {}
}

@Component
public class MethodInvokeRunner implements CommandLineRunner {
  @Value("#{messageFormatter.format('Welcome, ' + userService.getCurrentUser().name)}")
  private String welcomeMessage;

  @Value("#{T(java.time.LocalDateTime).now().plusDays(7)}")
  private java.time.LocalDateTime expirationDate;

  @Value("#{systemEnvironment['pack.app.enabled']?.toLowerCase() == 'true'}")
  private boolean notifyEnabled;

  @Override
  public void run(String... args) throws Exception {
    System.err.println(welcomeMessage);
    System.err.println(expirationDate);
    System.err.println(notifyEnabled);
  }
}

Sample output:

Welcome, Pack_xg
2025-09-13T17:22:02.591156
false

2.4 Regular Expressions and String Operations

SpEL supports regex matching and string manipulation.

@Component
public class ExpressionRunner implements CommandLineRunner {
  @Value("#{'${pack.sys.email}'.matches('^[A-Za-z0-9+_.-]+@(.+)$')}")
  private boolean isEmailValid;

  @Value("#{'${pack.sys.location}'.split(' ')[0]}")
  private String location;

  @Value("#{('${pack.sys.roles}'.toLowerCase() matches '.*admin.*') ? 'ADMIN' : 'USER'}")
  private String userType;

  @Override
  public void run(String... args) throws Exception {
    System.err.println(isEmailValid);
    System.err.println(location);
    System.err.println(userType);
  }
}

Configuration snippet:

pack:
  sys:
    email: [email protected]
    location: 新疆 乌鲁木齐
    roles: Admin,User,Guest

Result:

true
新疆
ADMIN

2.5 Math Operations and Ternary Expressions

SpEL can perform arithmetic and conditional logic.

@Service
public class DiscountService {
  public int calculateDiscount() { return 25; }
}

@Component
public class MathOperationAndTernaryRunner implements CommandLineRunner, BeanFactoryAware {
  private ConfigurableBeanFactory cbf;

  @Override
  public void run(String... args) throws Exception {
    SpelExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext sec = new StandardEvaluationContext();
    sec.addPropertyAccessor(new BeanFactoryAccessor());
    sec.addPropertyAccessor(new EnvironmentAccessor());
    sec.setBeanResolver(new BeanFactoryResolver(cbf));
    sec.setVariable("orderTotal", 100);
    sec.setVariable("maxDiscount", 10);

    Expression exp = parser.parseExpression("#orderTotal + (#orderTotal * 0.1)");
    System.err.println(exp.getValue(sec, Double.class));

    exp = parser.parseExpression("T(Math).round(#orderTotal * (100 - #maxDiscount) / 100.0)");
    System.err.println(exp.getValue(sec, Long.class));

    exp = parser.parseExpression("@discountService.calculateDiscount() > 20 ? 20 : @discountService.calculateDiscount()");
    System.err.println(exp.getValue(sec, Long.class));
  }

  @Override
  public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    if (beanFactory instanceof ConfigurableBeanFactory cbf) {
      this.cbf = cbf;
    }
  }
}

Output:

110.0
90
20
Javabackend developmentSpELSpring BootExpression Language
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

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.