Spring Expression Language (SpEL) 完全指南

Spring Expression Language (SpEL) 完全指南

目录

  1. SpEL 基础语法
  2. SpEL 操作符
  3. 集合与数组操作
  4. 变量与根对象
  5. 类型相关操作
  6. 在 Spring 中的应用场景
  7. 属性占位符 ${} 与 SpEL #{} 的区别
  8. Property Placeholder 配置
  9. 高级特性与注意事项
  10. 总结

1. SpEL 基础语法

SpEL 是 Spring 的动态表达式语言,用于运行时查询和操作对象。表达式以 #{ } 包裹。

1.1 字面量表达式

@Value("#{3.14}")          // 注入数字
private double pi;

@Value("#{'Hello'}")       // 注入字符串
private String message;

@Value("#{true}")          // 布尔值
private boolean isActive;

1.2 引用 Bean 和属性

@Component("userService")
public class UserService {
    public String getUsername() { return "Alice"; }
}

// 引用 Bean 的方法
@Value("#{userService.username}") 
private String username;    // 输出 "Alice"

1.3 调用静态方法

@Value("#{T(java.lang.Math).PI}") 
private double pi;          // 注入 Math.PI

@Value("#{T(java.util.UUID).randomUUID()}") 
private String uuid;        // 生成 UUID

2. SpEL 操作符

2.1 算术与比较操作符

@Value("#{1 + 2 * 3}")     // 7
private int sum;

@Value("#{user.age > 18}") // true/false user指的是根对象root的user属性,即IOC容器中某个名为user的bean
private boolean isAdult;

2.2 逻辑与三元操作符

@Value("#{isAdmin && isActive}") 
private boolean isValid;

@Value("#{user.age > 18 ? 'Adult' : 'Child'}") 
private String category;

2.3 Elvis 操作符(默认值)

@Value("#{user.nickname ?: 'Anonymous'}") 
private String nickname;    // 若 nickname 为 null,返回 'Anonymous'

2.4 安全导航操作符

@Value("#{user?.address?.city}") 
private String city;        // 避免 NullPointerException

3. 集合与数组操作

3.1 访问元素

@Value("#{list[0]}")        // 列表第一个元素
private String firstElement;

@Value("#{map['key']}")     // Map中key的值
private String value;

3.2 集合过滤(Selection)

@Value("#{users.?[age > 18]}") 
private List<User> adults;  // 过滤年龄 >18 的用户

3.3 集合投影(Projection)

@Value("#{users.![name]}") 
private List<String> names; // 提取所有用户的名字

4. 变量与根对象

4.1 变量定义

通过 EvaluationContext 动态设置变量:

EvaluationContext context = new StandardEvaluationContext();
context.setVariable("max", 100);

ExpressionParser parser = new SpelExpressionParser();
boolean result = parser.parseExpression("#max > 50").getValue(context, Boolean.class); // true

4.2 根对象(Root Object)

  • 定义:表达式默认操作的上下文对象。
  • 显式引用:通过 #root 访问。
User rootUser = new User("Alice", 25);
EvaluationContext context = new StandardEvaluationContext(rootUser);

// 直接访问根对象属性
String name = parser.parseExpression("name").getValue(context, String.class); // "Alice"

4.3 变量与根对象的区别

特性根对象变量
访问方式隐式(如 name)或 #root显式(如 #variable
设置方式通过 EvaluationContext 构造函数或方法context.setVariable()

5. 类型相关操作

5.1 类型判断

@Value("#{user instanceof T(com.example.User)}") 
private boolean isUserType;

5.2 构造对象

@Value("#{new com.example.User('Bob', 30)}") 
private User newUser;      // 需全限定类名

6. 在 Spring 中的应用场景

6.1 @Value 注解注入

@Value("#{systemProperties['user.timezone']}") 
private String timeZone;

6.2 XML 配置

<bean id="config" class="com.example.Config">
  <property name="max" value="#{T(java.lang.Math).random() * 100}"/>
</bean>

6.3 Spring Security

@PreAuthorize("hasRole('ADMIN') or #user.id == authentication.principal.id") // 这里的根对象是什么呢?
public void updateUser(User user) { ... }

7. 属性占位符 ${} vs SpEL #{}

7.1 ${}:读取 .properties 文件

# application.properties
app.name=MyApp
@Value("${app.name}") 
private String appName;     // 注入 "MyApp"

@Value("${app.timeout:3000}") // 默认值 3000
private int timeout;

7.2 混合使用

@Value("#{'Server: ' + ${app.name}}") 
private String serverInfo;  // 输出 "Server: MyApp"

8. Property Placeholder 配置

8.1 XML 配置

<context:property-placeholder location="classpath:app.properties"/>

8.2 Java 配置(非 Spring Boot)

@Configuration
@PropertySource("classpath:app.properties")
public class AppConfig {
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyConfig() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

8.3 Spring Boot 自动配置

默认加载 application.properties,无需额外配置。


9. 高级特性与注意事项

9.1 自定义函数

// 注册自定义方法
Method method = MathUtils.class.getMethod("square", double.class);
context.registerFunction("square", method);

// 表达式调用
@Value("#{#square(10)}") 
private double result;

9.2 安全性

// 禁用编译器以提高安全性
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.OFF, null);
ExpressionParser parser = new SpelExpressionParser(config);

9.3 性能优化

  • SpEL 首次执行后会编译为字节码,接近原生性能。
  • 避免在频繁调用的代码中使用复杂表达式。

10. 总结

  • SpEL 核心能力:动态计算、集合操作、安全导航。
  • ${}#{} 区别:前者读取属性,后者执行表达式。
  • 根对象:默认上下文对象,可通过 #root 显式访问。
  • 应用场景:动态配置、安全校验、条件注入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值