SpringBoot + Aviator + 规则中心:轻量级表达式引擎实现营销优惠动态计算

电商大促活动时,营销规则复杂多变,今天满300减50,明天买2送1,后天又变成阶梯式折扣?每次改规则都得改代码、重新发布,简直是开发人员的噩梦!今天就来聊聊如何用SpringBoot + Aviator表达式引擎,搭建一个灵活的营销规则中心,让运营同学也能轻松配置营销规则,再也不用求着开发改代码了!

一、营销规则的痛点

1.1 传统if-else的困境

在没有规则引擎之前,营销优惠计算通常是这样写的:

// 伪代码:传统的营销优惠计算
public BigDecimal calculateDiscount(Order order) {
    if (order.getUserLevel().equals("VIP")) {
        if (order.getAmount().compareTo(new BigDecimal("1000")) > 0) {
            return order.getAmount().multiply(new BigDecimal("0.8")); // VIP用户满1000打8折
        } else {
            return order.getAmount().multiply(new BigDecimal("0.9")); // VIP用户其他情况打9折
        }
    } else if (order.getUserLevel().equals("GOLD")) {
        if (order.getAmount().compareTo(new BigDecimal("500")) > 0) {
            return order.getAmount().multiply(new BigDecimal("0.85")); // 金牌用户满500打8.5折
        } else {
            return order.getAmount().multiply(new BigDecimal("0.95")); // 金牌用户其他情况打9.5折
        }
    } else {
        if (order.getAmount().compareTo(new BigDecimal("1000")) > 0) {
            return order.getAmount().multiply(new BigDecimal("0.9")); // 普通用户满1000打9折
        } else {
            return order.getAmount(); // 普通用户其他情况无折扣
        }
    }
}

这种写法的问题显而易见:

  • 代码复杂:复杂的if-else嵌套,难以维护
  • 修改困难:每次改规则都要改代码、重新发布
  • 扩展性差:新增规则类型需要修改核心代码
  • 测试困难:各种规则组合需要大量测试用例

1.2 业务规则变化频繁

电商行业的营销活动变化极快:

  • 节日促销:双11、双12、618等
  • 会员权益:不同等级用户享受不同优惠
  • 限时活动:秒杀、拼团、砍价等
  • 渠道差异:APP、小程序、H5不同渠道的差异化策略

面对这些变化,传统的硬编码方式显然跟不上节奏。

二、Aviator表达式引擎的优势

2.1 什么是Aviator

Aviator是一个高性能、轻量级的Java表达式引擎,专门用于动态求值表达式。它的特点:

  • 高性能:通过编译成Java字节码执行,性能优异
  • 轻量级:依赖包仅450K,核心部分仅70K
  • 功能丰富:支持算术运算、逻辑运算、正则表达式等
  • 安全可靠:不支持赋值语句和外部函数调用,防止安全问题

2.2 Aviator vs 其他规则引擎

特性AviatorDroolsQLExpressGroovy
性能⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
体积⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
学习成本⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
功能丰富度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
适用场景简单计算复杂业务规则中等复杂度通用脚本

推荐场景

  • Aviator:简单到中等复杂度的计算场景
  • Drools:复杂业务规则,有图形化编辑器需求
  • QLExpress:需要中文语法的业务场景

三、SpringBoot + Aviator 实战

3.1 项目依赖配置

首先在pom.xml中添加Aviator依赖:

<dependency>
    <groupId>com.googlecode.aviator</groupId>
    <artifactId>aviator</artifactId>
    <version>5.3.3</version>
</dependency>

3.2 核心代码实现

创建Aviator规则引擎服务:

@Component
@Slf4j
public class AviatorRuleEngine {
    
    /**
     * 缓存编译后的表达式,提高执行效率
     */
    private final Map<String, Expression> expressionCache = new ConcurrentHashMap<>();
    
    /**
     * 执行规则表达式
     */
    public Object executeRule(String expression, Map<String, Object> env) {
        try {
            // 检查缓存中是否存在编译后的表达式
            Expression compiledExpression = expressionCache.get(expression);
            if (compiledExpression == null) {
                // 编译表达式并缓存
                compiledExpression = AviatorEvaluator.compile(expression, true);
                expressionCache.put(expression, compiledExpression);
                log.debug("缓存表达式: {}", expression);
            }
            
            // 执行表达式
            Object result = compiledExpression.execute(env);
            log.debug("表达式执行结果: {} = {}", expression, result);
            return result;
        } catch (Exception e) {
            log.error("执行规则表达式失败: {}", expression, e);
            throw new RuntimeException("规则执行失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 验证表达式语法
     */
    public boolean validateExpression(String expression) {
        try {
            AviatorEvaluator.compile(expression, true);
            return true;
        } catch (Exception e) {
            log.error("表达式语法错误: {}", expression, e);
            return false;
        }
    }
}

3.3 营销规则服务实现

@Service
@Slf4j
public class RuleService {
    
    @Autowired
    private AviatorRuleEngine aviatorRuleEngine;
    
    /**
     * 根据订单金额和用户等级计算折扣
     */
    public Double calculateDiscount(Double orderAmount, String userLevel, String productCategory) {
        Map<String, Object> context = new HashMap<>();
        context.put("orderAmount", orderAmount);
        context.put("userLevel", userLevel);
        context.put("productCategory", productCategory);
        
        // 根据不同用户等级和订单金额计算折扣
        String ruleExpression;
        if ("VIP".equals(userLevel)) {
            // VIP用户:订单金额>1000打8折,否则打9折
            ruleExpression = "orderAmount > 1000 ? 0.8 : 0.9";
        } else if ("GOLD".equals(userLevel)) {
            // 金牌用户:订单金额>500打8.5折,否则打9.5折
            ruleExpression = "orderAmount > 500 ? 0.85 : 0.95";
        } else {
            // 普通用户:订单金额>1000打9折,否则无折扣
            ruleExpression = "orderAmount > 1000 ? 0.9 : 1.0";
        }
        
        Object result = aviatorRuleEngine.executeRule(ruleExpression, context);
        return Double.valueOf(result.toString());
    }
    
    /**
     * 计算满减优惠
     */
    public Double calculateCouponDiscount(Double orderAmount, String couponType) {
        Map<String, Object> context = new HashMap<>();
        context.put("orderAmount", orderAmount);
        context.put("couponType", couponType);
        
        String ruleExpression;
        if ("MANYIJIAN".equals(couponType)) {
            // 满减券:满200减20,满500减50
            ruleExpression = "orderAmount >= 500 ? 50 : (orderAmount >= 200 ? 20 : 0)";
        } else if ("ZHEKOU".equals(couponType)) {
            // 折扣券:满100打9折
            ruleExpression = "orderAmount >= 100 ? orderAmount * 0.1 : 0";
        } else {
            ruleExpression = "0";
        }
        
        Object result = aviatorRuleEngine.executeRule(ruleExpression, context);
        return Double.valueOf(result.toString());
    }
}

3.4 API接口实现

@RestController
@RequestMapping("/api/marketing")
@Slf4j
public class MarketingRuleController {
    
    @Autowired
    private RuleService ruleService;
    
    /**
     * 计算订单折扣
     */
    @PostMapping("/calculate-discount")
    public ResponseEntity<Map<String, Object>> calculateDiscount(@RequestBody Map<String, Object> request) {
        try {
            Double orderAmount = Double.valueOf(request.get("orderAmount").toString());
            String userLevel = request.get("userLevel").toString();
            String productCategory = request.get("productCategory").toString();
            
            Double discountRate = ruleService.calculateDiscount(orderAmount, userLevel, productCategory);
            
            Map<String, Object> result = new HashMap<>();
            result.put("originalAmount", orderAmount);
            result.put("discountRate", discountRate);
            result.put("discountedAmount", orderAmount * discountRate);
            result.put("savedAmount", orderAmount * (1 - discountRate));
            result.put("userLevel", userLevel);
            
            log.info("订单折扣计算完成: {}", result);
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            log.error("计算订单折扣失败", e);
            Map<String, Object> error = new HashMap<>();
            error.put("error", e.getMessage());
            return ResponseEntity.badRequest().body(error);
        }
    }
}

3.5 常用的营销规则表达式

// 1. 满减规则:满200减20,满500减50
String manjianRule = "orderAmount >= 500 ? 50 : (orderAmount >= 200 ? 20 : 0)";

// 2. 折扣规则:VIP用户打8折,金牌用户打8.5折
String zhekouRule = "userLevel == 'VIP' ? 0.8 : (userLevel == 'GOLD' ? 0.85 : 1.0)";

// 3. 阶梯规则:消费金额越高折扣越大
String jietiRule = "orderAmount >= 1000 ? 0.7 : (orderAmount >= 500 ? 0.8 : (orderAmount >= 200 ? 0.9 : 1.0))";

// 4. 组合规则:多条件判断
String complexRule = "(userLevel == 'VIP' and orderAmount >= 1000) ? 0.7 : " +
                    "(userLevel == 'GOLD' and orderAmount >= 500) ? 0.8 : 1.0";

// 5. 时间规则:特定时间段内有效
String timeRule = "orderTime >= '2023-11-11 00:00:00' and orderTime <= '2023-11-11 23:59:59' ? 0.5 : 1.0";

四、规则中心架构设计

4.1 整体架构

前端运营系统 ←→ 规则配置API ←→ 规则引擎服务 ←→ 缓存 ←→ 数据库
                                        ↓
                                   业务服务调用

4.2 规则存储设计

@Entity
@Table(name = "t_rule")
@Data
public class Rule {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    /**
     * 规则编码
     */
    @Column(unique = true, nullable = false)
    private String ruleCode;
    
    /**
     * 规则名称
     */
    private String ruleName;
    
    /**
     * 规则表达式
     */
    @Lob
    private String ruleExpression;
    
    /**
     * 规则描述
     */
    private String description;
    
    /**
     * 规则类型
     */
    private String ruleType;
    
    /**
     * 是否启用
     */
    private Boolean enabled = true;
    
    /**
     * 版本号
     */
    private Integer version = 1;
    
    /**
     * 创建时间
     */
    private LocalDateTime createTime = LocalDateTime.now();
    
    /**
     * 更新时间
     */
    private LocalDateTime updateTime = LocalDateTime.now();
}

4.3 规则缓存策略

@Service
public class CachedRuleService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private RuleRepository ruleRepository;
    
    private static final String RULE_CACHE_PREFIX = "rule:expression:";
    
    /**
     * 获取规则表达式(带缓存)
     */
    public String getRuleExpression(String ruleCode) {
        String cacheKey = RULE_CACHE_PREFIX + ruleCode;
        
        // 先从缓存获取
        String expression = (String) redisTemplate.opsForValue().get(cacheKey);
        if (expression != null) {
            return expression;
        }
        
        // 缓存未命中,从数据库获取
        Rule rule = ruleRepository.findByRuleCodeAndEnabledTrue(ruleCode);
        if (rule != null) {
            expression = rule.getRuleExpression();
            // 存入缓存,设置过期时间
            redisTemplate.opsForValue().set(cacheKey, expression, 300, TimeUnit.SECONDS);
            return expression;
        }
        
        return null;
    }
    
    /**
     * 更新规则时清除缓存
     */
    public void updateRule(Rule rule) {
        ruleRepository.save(rule);
        
        // 清除缓存
        String cacheKey = RULE_CACHE_PREFIX + rule.getRuleCode();
        redisTemplate.delete(cacheKey);
    }
}

五、最佳实践建议

5.1 规则设计原则

  1. 单一职责:每个规则只负责一个业务逻辑
  2. 可测试性:规则表达式应该易于单元测试
  3. 可读性:复杂的规则应该拆分成多个简单规则
  4. 性能考虑:避免过于复杂的嵌套表达式

5.2 安全性考虑

// 1. 表达式验证
public boolean validateRuleExpression(String expression) {
    try {
        // 编译表达式验证语法
        Expression compiled = AviatorEvaluator.compile(expression, true);
        return true;
    } catch (Exception e) {
        log.error("表达式验证失败: {}", expression, e);
        return false;
    }
}

// 2. 沙箱执行(可选)
public Object executeRuleSafely(String expression, Map<String, Object> env) {
    // 设置执行超时时间,防止死循环
    Map<String, Object> envWithTimeout = new HashMap<>(env);
    envWithTimeout.put("max_execution_time", 1000); // 1秒超时
    
    return AviatorEvaluator.execute(expression, envWithTimeout);
}

5.3 监控和日志

@Service
@Slf4j
public class MonitoredRuleService {
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    public Object executeRuleWithMonitor(String ruleCode, String expression, Map<String, Object> env) {
        Timer.Sample sample = Timer.start(meterRegistry);
        
        try {
            Object result = aviatorRuleEngine.executeRule(expression, env);
            
            // 记录成功指标
            sample.stop(Timer.builder("rule.execution.time")
                .tag("rule_code", ruleCode)
                .tag("result", "success")
                .register(meterRegistry));
                
            log.info("规则执行成功: ruleCode={}, result={}", ruleCode, result);
            return result;
        } catch (Exception e) {
            // 记录失败指标
            sample.stop(Timer.builder("rule.execution.time")
                .tag("rule_code", ruleCode)
                .tag("result", "error")
                .register(meterRegistry));
                
            log.error("规则执行失败: ruleCode={}, expression={}", ruleCode, expression, e);
            throw e;
        }
    }
}

5.4 规则版本管理

// 规则版本管理
@Entity
@Table(name = "t_rule_version")
@Data
public class RuleVersion {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String ruleCode;
    private String ruleExpression;
    private Integer version;
    private String description;
    private LocalDateTime createTime;
    private String createdBy;
    
    // 是否为当前版本
    private Boolean current = false;
}

六、总结

通过SpringBoot + Aviator的组合,我们可以轻松构建一个灵活的营销规则引擎:

  1. 业务灵活性:运营人员可以动态配置营销规则,无需开发介入
  2. 系统性能:Aviator高性能表达式引擎,满足高并发场景
  3. 维护性:规则与代码分离,降低维护成本
  4. 扩展性:支持复杂的业务规则表达式

这套方案特别适合电商、金融等营销活动频繁变化的业务场景。记住,技术的价值在于解决业务问题,选择合适的工具才能事半功倍!

掌握了这套规则引擎方案,相信你再面对复杂的营销规则时会更加从容不迫,让运营同学也能轻松玩转营销活动!


本文由服务端技术精选原创,转载请注明出处。关注我们,获取更多后端技术干货!


标题:SpringBoot + Aviator + 规则中心:轻量级表达式引擎实现营销优惠动态计算
作者:jiangyi
地址:http://jiangyi.space/articles/2026/01/08/1767880888150.html

    0 评论
avatar