第一次接触Easy Rules时,我完全被它简洁的API设计惊艳到了。这个轻量级的Java规则引擎,用注解和链式调用的方式,把原本复杂的业务规则判断变得像搭积木一样简单。但真正让我决定在生产环境使用它的,是在电商促销系统重构中的一次实践。
当时我们需要处理几十种优惠券的叠加规则,传统的if-else写法已经让代码臃肿不堪。记得有个"满300减50再打9折"的叠加场景,老代码里嵌套了7层条件判断。而改用Easy Rules后,我们把每种优惠条件拆解成独立规则,用UnitRuleGroup组合处理,代码量直接减少了60%。
假设我们要实现以下优惠规则:
首先定义新用户规则:
java复制@Rule(name = "NewUserRule", description = "新用户首单立减20元")
public class NewUserRule {
@Condition
public boolean isNewUser(@Fact("order") Order order) {
return order.getUser().isNewUser() && order.isFirstOrder();
}
@Action
public void applyDiscount(@Fact("order") Order order) {
order.applyDiscount(20, "新用户首单优惠");
}
@Priority
public int getPriority() {
return 1; // 最高优先级
}
}
接着实现满减规则:
java复制@Rule(name = "Over200Discount", description = "满200减30")
public class Over200Rule {
@Condition
public boolean checkAmount(@Fact("order") Order order) {
return order.getTotalAmount() >= 200;
}
@Action
public void applyDiscount(@Fact("order") Order order) {
order.applyDiscount(30, "满200减30");
}
@Priority
public int getPriority() {
return 2;
}
}
在电商场景中,合理的参数配置能显著提升性能:
java复制RulesEngineParameters parameters = new RulesEngineParameters()
.skipOnFirstAppliedRule(false) // 允许多规则叠加
.skipOnFirstFailedRule(true) // 遇到异常规则立即终止
.rulePriorityThreshold(10); // 限制最高优先级
RulesEngine engine = new DefaultRulesEngine(parameters);
特别提醒:当处理金融级优惠计算时,建议设置skipOnFirstFailedRule为true,避免部分规则失败导致金额计算异常。
java复制public class CouponRuleGroup extends UnitRuleGroup {
public CouponRuleGroup(Object... rules) {
Arrays.stream(rules).forEach(this::addRule);
}
@Override
public int getPriority() {
return 3; // 组合规则优先级
}
}
// 使用示例
Rules rules = new Rules();
rules.register(new NewUserRule());
rules.register(new Over200Rule());
rules.register(new CouponRuleGroup(
new NewUserRule(),
new Over200Rule()
));
比如"满减"和"折扣"二选一的场景:
java复制public class MutualExclusionGroup extends ConditionalRuleGroup {
public MutualExclusionGroup(Object... rules) {
Arrays.stream(rules)
.sorted(Comparator.comparingInt(r -> ((Rule)r).getPriority()))
.forEach(this::addRule);
}
@Override
public int getPriority() {
return 0; // 最高优先级组
}
}
建议监控这些关键指标:
可以通过自定义RulesEngineListener实现:
java复制engine.registerRuleListener(new RuleListener() {
@Override
public void beforeExecute(Rule rule, Facts facts) {
long startTime = System.currentTimeMillis();
facts.put(rule.getName()+"_start", startTime);
}
@Override
public void afterExecute(Rule rule, Facts facts) {
long duration = System.currentTimeMillis() -
facts.get(rule.getName()+"_start");
monitor.recordDuration(rule.getName(), duration);
}
});
坑点1:规则执行顺序混乱
解决方案:明确设置@Priority,建议采用10的倍数(如10,20,30)方便后续插入新规则
坑点2:规则间事实污染
解决方案:为每个规则定义独立Fact命名空间,例如:
java复制@Action
public void action(@Fact("order.discount") BigDecimal discount) {
// 使用嵌套路径避免冲突
}
坑点3:性能瓶颈
解决方案:对高频规则启用skipOnFirstAppliedRule,并考虑使用RuleProxy模式:
java复制Rule rule = RuleProxy.asRule(new Rule() {
@Condition
public boolean when(@Fact("data") Data data) {
return data.isValid();
}
// ...
});
对于大型电商系统,建议采用分层规则架构:
示例架构代码:
java复制public class RuleEngineFacade {
private RulesEngine basicEngine;
private RulesEngine compositeEngine;
private RulesEngine riskEngine;
public void execute(Order order) {
Facts facts = new Facts();
facts.put("order", order);
// 第一层:基础优惠
basicEngine.fire(basicRules, facts);
// 第二层:组合优惠
if(order.hasCompositeCoupons()) {
compositeEngine.fire(compositeRules, facts);
}
// 第三层:风控校验
riskEngine.fire(riskRules, facts);
}
}
在日均百万订单的系统中,这种分层结构能使规则执行时间控制在50ms以内,相比传统方案性能提升4倍。