找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

578

积分

0

好友

77

主题
发表于 前天 10:47 | 查看: 20| 回复: 0

日常开发中,你是否遇到过这些痛点?电商促销规则频繁变更、金融风控策略需实时调整、系统参数校验逻辑多样化。硬编码修改不仅耗时,还需反复测试发版,严重拖累了业务迭代的效率。

QLExpress作为阿里开源的轻量规则引擎,能完美解决「业务规则与代码解耦」的核心需求。搭配Spring Boot的工程化能力,可快速实现规则动态配置、实时生效,无需开发介入即可满足业务需求。下文将从「使用场景→0到1集成案例→核心优势」三个维度进行拆解,助你快速上手落地。

一、QLExpress 核心使用场景

QLExpress主打「轻量、高效、灵活」,适合中小场景的动态规则需求。每个核心场景均搭配极简实操代码,方便直接复用。

1. 电商领域:动态促销规则

场景描述:大促期间,业务人员需根据销量、用户等级、订单金额调整优惠策略(如新用户满减、会员折扣、跨店满减叠加),要求规则实时生效,无需发版。

落地价值:业务人员通过后台配置规则表达式,系统自动执行计算,规则迭代效率大幅提升。

// 核心规则表达式(业务人员可直接配置)
String promotionRule = “isNewUser ? (totalAmount>=100 ? (totalAmount-50)*0.8 : totalAmount) : “ +
“(memberLevel>=3 ? totalAmount*0.75 : totalAmount - (totalAmount/200*30))”;
// 执行逻辑(极简demo)
DefaultContext<String, Object> context = new DefaultContext<>();
context.put(“isNewUser”, true);
context.put(“totalAmount”, 600.0);
context.put(“memberLevel”, 1);
Double result = (Double) new ExpressRunner().execute(promotionRule, context, null, true, false);
System.out.println(“实付金额:“ + BigDecimal.valueOf(result).setScale(2)); // 输出440.00

2. 金融领域:风控校验规则

场景描述:贷款申请、支付风控时,需根据客户信用评级、负债比例、市场波动率动态调整审批门槛,且需支持多维度规则组合校验。

落地价值:风控团队独立调整规则,响应市场风险变化的时间从数天缩短至分钟级,有效降低不良风险。

// 风控规则表达式(多条件组合)
String riskRule = “creditRating>=4 && debtRatio<0.3 || (creditRating>=3 && debtRatio<0.4 && marketVol<=0.5)”;
// 绑定Spring服务获取实时数据(实操核心)
ExpressRunner runner = new ExpressRunner();
MarketService marketService = new MarketService(); // 实际为Spring注入Bean
runner.addFunctionOfServiceMethod(“getMarketVol”, marketService, “getMarketVolatility”, new Class[]{}, null);
// 执行风控校验
DefaultContext<String, Object> riskContext = new DefaultContext<>();
riskContext.put(“creditRating”, 3);
riskContext.put(“debtRatio”, 0.35);
Boolean pass = (Boolean) runner.execute(“marketVol=getMarketVol();” + riskRule, riskContext, null, true, false);
System.out.println(“风控是否通过:“ + pass); // 输出true

3. 系统领域:参数校验与逻辑判断

场景描述:接口入参校验(如手机号、邮箱格式、金额范围)、流程分支动态判断(如不同角色走不同审批流程),需支持自定义校验逻辑。

落地价值:替代大量if-else代码,减少代码冗余,校验逻辑可复用、可动态修改。

// 自定义参数校验函数(注册到QLExpress)
ExpressRunner runner = new ExpressRunner();
runner.addFunction(“checkMobile”, (String mobile) -> mobile.matches(“^1[3-9]\\d{9}$”));
// 校验规则表达式
String checkRule = “checkMobile(mobile) && amount>0 && amount<=10000”;
// 执行校验
DefaultContext<String, Object> checkContext = new DefaultContext<>();
checkContext.put(“mobile”, “13800138000”);
checkContext.put(“amount”, 5000.0);
Boolean valid = (Boolean) runner.execute(checkRule, checkContext, null, true, false);
System.out.println(“参数是否合法:“ + valid); // 输出true

4. 物联网/政务:动态配置逻辑

场景描述:物联网设备阈值告警规则(如温度超过X度触发告警)、政务流程合规校验规则,需适配不同地区/设备的个性化需求。

落地价值:无需修改设备端/服务端代码,通过规则配置适配多场景,显著降低维护成本。

// 设备告警规则(可按设备编号动态配置)
String deviceAlarmRule = “temperature>maxTemp || humidity>maxHumidity ? ‘ALARM’ : ‘NORMAL’”;
// 多设备适配(模拟不同设备阈值)
Map<String, Map<String, Double>> deviceConfig = new HashMap<>();
deviceConfig.put(“device001”, Map.of(“maxTemp”, 35.0, “maxHumidity”, 80.0));
deviceConfig.put(“device002”, Map.of(“maxTemp”, 40.0, “maxHumidity”, 75.0));
// 执行设备状态判断
ExpressRunner runner = new ExpressRunner();
DefaultContext<String, Object> deviceContext = new DefaultContext<>();
deviceContext.put(“temperature”, 38.0);
deviceContext.put(“humidity”, 70.0);
deviceContext.putAll(deviceConfig.get(“device001”));
String status = (String) runner.execute(deviceAlarmRule, deviceContext, null, true, false);
System.out.println(“设备状态:“ + status); // 输出ALARM

二、从0到1:Spring Boot 3 集成QLExpress完整案例

本案例以「电商订单实时优惠计算」为场景,实现从依赖引入、引擎配置、规则编写到接口落地的全流程,代码可直接复制复用。

1. 环境准备

基础环境:JDK 17+(Spring Boot 3.x 最低兼容JDK 17)、Maven 3.6+、Spring Boot 3.x

引入依赖:在pom.xml中添加QLExpress依赖(排除冲突依赖,适配生产环境)

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>QLExpress</artifactId>
<version>3.3.3</version>
<exclusions>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</exclusion>
</exclusions>
</dependency>

2. 初始化QLExpress引擎(Spring配置类)

配置引擎参数(安全沙箱、缓存优化、预编译规则),确保生产级可用:

import com.ql.util.express.ExpressRunner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@Slf4j
public class QLExpressConfig{

@Bean
public ExpressRunner expressRunner(){
        ExpressRunner runner = new ExpressRunner();
// 1. 开启安全沙箱,禁止危险操作(如new、循环)
        runner.setSandboxMode(true);
// 2. 开启编译缓存,提升重复规则执行效率
        runner.setCacheExpress(true);
// 3. 配置缓存大小(LRU淘汰,避免内存溢出)
        System.setProperty(“org.qlExpress.cacheSize”, “500”);
// 4. 预编译高频规则(启动时加载,减少运行时耗时)
        preCompileHighFreqRules(runner);
return runner;
    }

// 预编译电商优惠高频规则
private void preCompileHighFreqRules(ExpressRunner runner){
        String[] highFreqRules = {
“isNewUser && totalAmount > 500 ? totalAmount * 0.8 : totalAmount”,
“memberLevel >= 3 ? totalAmount * 0.75 : totalAmount”
        };
for (String rule : highFreqRules) {
try {
                runner.compile(rule, null, true);
            } catch (Exception e) {
                log.error(“预编译规则失败:{}”, rule, e);
            }
        }
    }
}

3. 定义业务模型与规则存储

规则存储建议用数据库或配置中心(本文用常量模拟,实际可对接Nacos/Apollo):

// 1. 订单业务模型
import lombok.Data;
import java.math.BigDecimal;

@Data
public class Order{
// 用户ID
private String userId;
// 是否新用户
private boolean isNewUser;
// 订单金额
private BigDecimal totalAmount;
// 会员等级(1-5级)
private Integer memberLevel;
}

// 2. 规则存储类(实际对接配置中心,支持动态更新)
public class DiscountRuleStorage{
// 业务人员配置的复杂优惠规则
public static String ORDER_DISCOUNT_RULE = “{
  // 新用户优惠:满100减50后再8折,不满100原价
  if (isNewUser) {
    return totalAmount >= 100 ? (totalAmount - 50) * 0.8 : totalAmount;
  }
  // 3级及以上会员:75折+满500加赠100积分
  else if (memberLevel >= 3) {
    return totalAmount * 0.75 + (totalAmount > 500 ? 100 : 0);
  }
  // 普通老用户:每满200减30
  else {
    return totalAmount - (totalAmount / 200 * 30);
  }
}”;
}

4. 编写规则执行服务(核心业务逻辑)

封装规则执行方法,对接Spring服务,实现订单金额计算:

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;

@Service
public class OrderDiscountService{

@Autowired
private ExpressRunner expressRunner;

// 计算订单实付金额(对外提供服务)
public BigDecimal calculatePayAmount(Order order) throws Exception {
// 1. 封装上下文变量(将订单数据传入规则引擎)
        DefaultContext<String, Object> context = new DefaultContext<>();
        context.put(“isNewUser”, order.isNewUser());
        context.put(“totalAmount”, order.getTotalAmount().doubleValue());
        context.put(“memberLevel”, order.getMemberLevel());

// 2. 执行规则(复用缓存,提升效率)
        Double result = (Double) expressRunner.execute(
            DiscountRuleStorage.ORDER_DISCOUNT_RULE,
            context,
null,  // 不收集错误信息
true,  // 启用缓存
false // 不输出执行日志
        );

// 3. 结果格式化(保留2位小数)
return BigDecimal.valueOf(result).setScale(2, RoundingMode.HALF_UP);
    }
}

5. 编写接口测试(验证效果)

提供REST接口,模拟不同场景的订单优惠计算:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;

@RestController
public class OrderController{

@Autowired
private OrderDiscountService discountService;

@PostMapping(“/order/calculate”)
public BigDecimal calculateOrder(@RequestBody Order order) throws Exception {
return discountService.calculatePayAmount(order);
    }
}

6. 测试验证(3种场景)

用Postman调用接口,传入不同订单参数,验证规则执行结果:

// 场景1:新用户,订单金额600元
{
“userId”: “1001”,
“isNewUser”: true,
“totalAmount”: 600.00,
“memberLevel”: 1
}
// 计算结果:(600-50)*0.8=440.00  ✅

// 场景2:3级会员,订单金额500元
{
“userId”: “1002”,
“isNewUser”: false,
“totalAmount”: 500.00,
“memberLevel”: 3
}
// 计算结果:500*0.75=375.00(不满500无积分) ✅

// 场景3:普通老用户,订单金额400元
{
“userId”: “1003”,
“isNewUser”: false,
“totalAmount”: 400.00,
“memberLevel”: 2
}
// 计算结果:400 - (400/200*30) = 340.00  ✅

7. 动态更新规则(生产级优化)

实际业务中,可将DiscountRuleStorage对接Nacos等配置中心,业务人员修改规则表达式后,通过监听配置变更刷新规则,无需重启服务:

// 伪代码:监听Nacos配置变更
@NacosConfigListener(dataId = “order-discount-rule”, groupId = “DEFAULT_GROUP”)
public void refreshDiscountRule(String newRule){
    DiscountRuleStorage.ORDER_DISCOUNT_RULE = newRule;
    log.info(“优惠规则已动态更新:{}”, newRule);
}

三、QLExpress 核心优势

1. 轻量无侵入,集成成本低

Jar包仅约250k,无复杂依赖,无需额外部署独立服务,直接嵌入Spring Boot 3项目,开箱即用。对比Drools(依赖繁重、需独立部署),中小项目集成效率提升显著。

// 仅需1行核心依赖(排除冲突后),无其他附加依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>QLExpress</artifactId>
<version>3.3.3</version>
<exclusions>...</exclusions>
</dependency>

2. 规则与代码解耦,业务迭代快

规则表达式可存储在配置中心,业务人员修改后实时生效,无需开发介入改代码、发版。对比传统硬编码,彻底摆脱「改规则→测代码→发版本」的冗长流程。

// 传统硬编码(改规则需改代码)
public BigDecimal calculateOld(Order order){
if (order.isNewUser()) {
return order.getTotalAmount().subtract(new BigDecimal(50)).multiply(new BigDecimal(0.8));
    } else if (order.getMemberLevel() >= 3) {
return order.getTotalAmount().multiply(new BigDecimal(0.75));
    }
// 更多if-else...
return order.getTotalAmount();
}

// QLExpress方案(规则存配置中心,动态刷新)
public BigDecimal calculateNew(Order order) throws Exception {
    String rule = configService.getConfig(“order-discount-rule”); // 从Nacos/Apollo获取
    DefaultContext<String, Object> context = new DefaultContext<>();
    context.put(“isNewUser”, order.isNewUser());
// 封装变量...
return BigDecimal.valueOf((Double) runner.execute(rule, context, null, true, false));
}

3. 高效安全,适配生产环境

支持预编译+缓存复用,执行效率接近原生Java;内置安全沙箱,可禁用危险操作、限制执行时长,避免恶意脚本和死循环风险,适配Spring Boot 3生产级要求。

// 高效+安全组合配置(生产直接复用)
@Bean
public ExpressRunner expressRunner(){
    ExpressRunner runner = new ExpressRunner();
    runner.setSandboxMode(true); // 开启沙箱
    runner.setCacheExpress(true); // 开启缓存
    runner.setExecuteTimeout(300); // 限制执行时长300ms
// 禁用危险操作符
    runner.addOperatorWithAlias(“new”, null, null);
    runner.addOperatorWithAlias(“for”, null, null);
// 预编译高频规则
    preCompileRules(runner);
return runner;
}

4. 灵活扩展,适配多场景

支持自定义函数、Spring组件联动、宏定义等扩展能力,可无缝对接电商、金融、物联网等多场景,且支持多线程并发执行(线程安全)。

// 1. 注册自定义函数
runner.addFunction(“calculateTax”, (BigDecimal amount) -> amount.multiply(new BigDecimal(0.09)));
// 2. 联动Spring服务
runner.addFunctionOfServiceMethod(“getUserLevel”, userService, “getLevelByUserId”, new Class[]{String.class}, null);
// 3. 宏定义简化规则
runner.addMacro(“HIGH_LEVEL”, “memberLevel>=4”);
// 组合使用规则表达式
String complexRule = “HIGH_LEVEL ? calculateTax(totalAmount) + totalAmount : totalAmount”;
DefaultContext<String, Object> context = new DefaultContext<>();
context.put(“totalAmount”, new BigDecimal(1000));
context.put(“memberLevel”, 4);
BigDecimal result = (BigDecimal) runner.execute(complexRule, context, null, true, false);

5. 语法简洁,学习成本低

语法类似JavaScript,弱类型无需严格定义变量,业务人员1小时即可上手编写规则,跨团队协作成本极低。对比Groovy(语法复杂)、SpEL(仅适用于Spring),通用性更强。

// QLExpress规则(简洁易懂,业务人员可直接编写)
String simpleRule = “isNewUser && totalAmount>500 ? totalAmount*0.8 : (memberLevel>=3 ? totalAmount*0.75 : totalAmount)”;

// 对比Groovy(语法相对繁琐)
String groovyRule = “”“
    if (isNewUser && totalAmount > 500) {
        return totalAmount * 0.8
    } else {
        return memberLevel >=3 ? totalAmount * 0.75 : totalAmount
    }
”“”.stripIndent();

总结

QLExpress作为轻量规则引擎,其核心价值在于「以极低的集成成本,实现业务规则动态化」,尤其适合中小场景的规则迭代需求。通过本文从0到1的电商案例,你可直接复制代码落地,快速适配自身业务场景。

未来,可结合配置中心实现规则分布式管理,进一步提升业务效率。建议从简单场景(如参数校验、订单计算)入手尝试,逐步落地到复杂业务,让技术真正为业务提效。更多技术实践和Java相关的深度讨论,欢迎访问云栈社区进行交流。




上一篇:HardenedBSD安全强化系统详解:基于FreeBSD的现代防御技术实践
下一篇:ARM Mac快速搭建Kubernetes集群:基于Vagrant与VMware Fusion的完整指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-24 02:49 , Processed in 0.487566 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表