Solon Expression Language (SnEL):轻量高效的Java表达式引擎

一、SnEL 是什么?

Solon Expression Language(简称SnEL)是 Solon 生态体系中的轻量级表达式引擎,专为Java开发者设计。它采用独特的"求值表达式"模型,通过简洁的语法实现复杂逻辑处理,同时保持极高的执行效率和安全性。

项目地址:

二、核心特性解析

1. 安全可靠的表达式引擎

  • 无副作用设计 :禁止new实例化、控制语句等危险操作
  • 上下文隔离 :通过StandardContext严格管控变量访问范围

2. 丰富的表达式能力

java 复制代码
// 复杂逻辑表达式示例
String expr = """
    ((age > 18 AND salary < 5000) OR NOT isMarried) 
    AND tags IN ['vip','premium'] 
    OR level == 'gold'""";

支持功能主要包括:

  • 基础运算:算术、比较、逻辑运算
  • 集合操作:IN/NOT IN集合判断
  • 嵌套访问:多级对象属性/方法调用
  • 静态方法:直接调用类静态方法
  • 三元运算:条件表达式支持

更多参考官网:《SnEL 求值表达式语法和能力说明》

3. 独创的模板引擎

双模式模板处理:

java 复制代码
// 求值表达式模板
SnEL.evalTmpl("订单总额:#{order.amount * 0.95}");

// 属性表达式模板(带默认值)
SnEL.evalTmpl("配置参数:${server.timeout:3000}");

三、企业级功能深度解析

1. 上下文增强方案

java 复制代码
// 标准Map上下文
Map<String,Object> ctx = new HashMap<>();
ctx.put("user", userService.getCurrent());

// 增强型Bean上下文
StandardContext context = new StandardContext(userEntity);
context.properties(configProps); // 绑定配置属性

// 虚拟root访问
SnEL.eval("root.id > 1000", context);

2. 多场景表达式转换

基于AST的通用转换接口:

java 复制代码
Expression expr = SnEL.parse("age > 18 AND status=='active'");

// 转换为Redis查询语法
String redisFilter = RedisFilterTransformer.getInstance().transform(expr);

// 转换为Elasticsearch DSL
Map<String,Object> esQuery = ElasticsearchFilterTransformer.getInstance().transform(expr);

// 输出语法树结构
PrintUtil.printTree(expr);
转换器类型 输出示例 应用场景
Redis (@age:[18 +inf] @status:{active}) 缓存查询
Milvus ((metadata["age"] > 18) and (metadata["status"] == "active")) 向量数据库
Elasticsearch {bool={must=[{range={age={gt=18}}}, {term={status={value=active}}}]}} 全文检索
SQL WHERE age > 18 AND status='active' 数据库查询

四、典型应用场景

  • 动态规则引擎:金融风控规则配置
  • 智能路由:微服务调用条件路由
  • 低代码平台:表单校验逻辑动态配置
  • 数据分析:实时数据过滤与计算

五、快速入门

1. 添加依赖

xml 复制代码
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-expression</artifactId>
    <version>最新版本</version>
</dependency>

2. 基础用法示例

java 复制代码
public class Demo {
    public static void main(String[] args) {
        Map<String,Object> context = new HashMap<>();
        context.put("price", 99.5);
        context.put("discount", 0.8);
        
        Object result = SnEL.eval("price * discount > 50", context);
        System.out.println("是否符合条件:" + result);
    }
}

3. 性能优化建议

  • 复用解析结果:对固定表达式使用 SnEL.parse() 缓存 AST
  • 上下文优化:复杂对象优先使用 StandardContext
  • 避免频繁解析:高并发场景预编译表达式

六、企业实践案例

案例1:电商促销系统

java 复制代码
// 动态计算促销条件
String rule = """
    (user.level IN ['VIP','SVIP'] OR order.amount > 1000) 
    AND inventory.stock > 0 
    AND NOT blacklist.contains(user.id)""";
    
Boolean rst = SnEL.eval(rule, context);

案例2:物联网数据处理

java 复制代码
// 设备数据过滤规则
String filter = """
    (data.temperature > 38.5 OR data.humidity < 20) 
    AND meta.deviceType == 'medical'""";

// 转换为MQTT Topic过滤语法(需要自已定制 IotTransformer)
String mqttFilter = IotTransformer.transform(SnEL.parse(filter));
相关推荐
77qqqiqi20 分钟前
解决忘记修改配置密码而无法连接nacos的问题
java·数据库·docker·微服务
ALLSectorSorft34 分钟前
相亲小程序用户注册与登录系统模块搭建
java·大数据·服务器·数据库·python
琢磨先生David1 小时前
Java 垃圾回收机制:自动化内存管理的艺术与科学
java
岁忧1 小时前
(nice!!!)(LeetCode 每日一题) 2561. 重排水果 (哈希表 + 贪心)
java·c++·算法·leetcode·go·散列表
阿华的代码王国1 小时前
【Android】RecyclerView实现新闻列表布局(1)适配器使用相关问题
android·xml·java·前端·后端
码农BookSea1 小时前
自研 DSL 神器:万字拆解 ANTLR 4 核心原理与高级应用
java·后端
lovebugs2 小时前
Java并发编程:深入理解volatile与指令重排
java·后端·面试
慕y2742 小时前
Java学习第九十一部分——OkHttp
java·开发语言·学习
caisexi2 小时前
Windows批量启动java服务bat脚本
java·windows·python
NullPointerExpection2 小时前
win10 环境删除文件提示文件被使用无法删除怎么办?
java·ide·windows·win10