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 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.1Safe 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
false2.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,GuestResult:
true
新疆
ADMIN2.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
20Spring 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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
