QLExpress是阿里开源的一款轻量级Java动态脚本引擎,常用于规则判断、公式计算等需要动态逻辑的场景。下面是其核心使用方法和一个实际项目集成示例。
🚀 快速入门
以下表格汇总了从安装到执行的关键步骤:
| 步骤 | 关键内容 | 说明与示例 |
|---|---|---|
| 1. 添加依赖 | Maven坐标 | 在pom.xml中添加:<dependency> <groupId>com.alibaba</groupId> <artifactId>QLExpress</artifactId> <version>3.3.4</version> </dependency> |
| 2. 核心API | ExpressRunner |
核心执行器,负责脚本的编译与运行。 |
DefaultContext |
用于向脚本传递参数的上下文对象。 | |
| 3. 执行脚本 | execute方法 |
基础执行代码: ExpressRunner runner = new ExpressRunner(); DefaultContext<String, Object> context = new DefaultContext<>(); context.put("a", 10); Object result = runner.execute("a * 2", context, null, true, false); System.out.println(result); // 输出 20 |
🧩 核心功能与技巧
掌握基础后,你可以利用QLExpress更灵活地处理复杂逻辑:
-
自定义函数与方法注入
如果脚本需要调用特定业务逻辑,可以注入自定义函数或Java方法。
// 1. 添加自定义函数 runner.addFunction("isVIP", new Operator() { @Override public Object executeInner(Object[] list) { Integer level = (Integer) list[0]; return level != null && level >= 3; } }); // 脚本中调用:isVIP(userLevel) // 2. 注入对象方法(例如StringUtils) runner.addFunctionOfServiceMethod("strLength", new StringUtils(), "length", new Class[]{String.class}, null); // 脚本中调用:strLength('hello')对于更复杂的方法调用,QLExpress支持通过
addFunctionOfClassMethod或绑定静态方法。 -
使用宏定义简化脚本
对于频繁使用的复杂表达式,可以定义为宏来简化脚本编写。
runner.addMacro("是否优质客户", "平均消费 > 1000 && 投诉次数 < 2"); // 后续脚本中可直接使用:“是否优质客户” 作为判断条件 -
安全控制至关重要
如果脚本允许外部输入,必须开启安全沙箱模式,防止恶意代码调用。
java
// 开启沙箱模式,禁止所有Java类的直接调用 QLExpressRunStrategy.setSandBoxMode(true); // 通过白名单,仅允许调用安全的方法 QLExpressRunStrategy.addSecureMethod(SafeService.class, "safeMethod");
💡 项目集成示例:动态风控规则
以搭建一个简单的风控规则引擎为例,展示如何将QLExpress集成到Spring Boot项目中。
-
第一步:设计规则模型
@Data public class RiskRule { private String ruleId; // 规则ID,如 "RULE_AMOUNT" private String ruleName; // 规则名称,如 "交易金额阈值" private String expression; // QL表达式,如 "amount > 10000" private String riskLevel; // 命中后的风险等级,如 "HIGH" private Integer priority; // 执行优先级 } -
第二步:封装规则执行服务
@Service public class RiskEngineService { // 缓存编译后的规则,提升性能 private Map<String, IExpress<String>> ruleCache = new ConcurrentHashMap<>(); private ExpressRunner runner = new ExpressRunner(); public RiskResult evaluate(Transaction transaction, List<RiskRule> rules) { // 1. 准备脚本上下文,注入交易参数 DefaultContext<String, Object> context = new DefaultContext<>(); context.put("amount", transaction.getAmount()); context.put("userId", transaction.getUserId()); // ... 注入其他参数 // 2. 按优先级排序并执行规则 rules.sort(Comparator.comparing(RiskRule::getPriority)); for (RiskRule rule : rules) { try { IExpress<String> compiledExpress = ruleCache.computeIfAbsent( rule.getRuleId(), id -> runner.compile(rule.getExpression(), null) // 编译并缓存 ); // 3. 执行规则 Boolean isHit = (Boolean) compiledExpress.execute(context, null, true, false); if (isHit != null && isHit) { return new RiskResult(true, rule.getRiskLevel(), rule.getRuleName()); } } catch (Exception e) { // 记录规则执行异常,但不中断流程 log.error("执行规则[{}]异常", rule.getRuleId(), e); } } // 4. 所有规则均未命中,返回安全 return RiskResult.pass(); } } -
第三步:模拟交易测试
@RestController @RequestMapping("/risk") public class RiskController { @Autowired private RiskEngineService riskEngineService; @Autowired private RiskRuleRepository ruleRepository; // 假设从数据库加载规则 @PostMapping("/evaluate") public RiskResult evaluate(@RequestBody Transaction transaction) { List<RiskRule> activeRules = ruleRepository.findActiveRules(); return riskEngineService.evaluate(transaction, activeRules); } }
🔍 注意事项与调试
实际使用中,请注意以下几点:
-
性能:对高频执行的规则使用预编译缓存(如上例所示),避免重复解析。
-
错误处理 :务必捕获
QLException,并根据业务需求转换为友好提示。 -
调试 :在开发阶段,可以通过
runner.setIsTrace(true)开启执行轨迹跟踪,方便排查逻辑问题。
🤔 如何选择与进一步学习
QLExpress适合规则简单、对性能敏感、需要快速集成的场景。如果你的规则极其复杂或需要完整的DSL支持,可以考虑更重的规则引擎(如Drools)。
进一步学习,你可以:
-
阅读官方GitHub仓库的文档和测试用例。
-
参考社区的技术文章。