基于SpringBoot + QLExpress打造动态规则引擎:让业务规则不再束缚代码!

基于SpringBoot + QLExpress打造动态规则引擎:让业务规则不再束缚代码!

每次业务规则变动都需要修改代码、重新打包、上线部署?客户临时想要调整折扣规则、风控策略或者计费逻辑,你就得加班加点改代码?今天就来聊聊如何基于SpringBoot + QLExpress打造一个强大的动态规则引擎,让业务规则变得灵活可控,再也不用担心频繁变更了!

一、为什么需要动态规则引擎?

在开始技术实现之前,我们先来理解为什么动态规则引擎如此重要。

1.1 传统业务规则的痛点

// 传统业务规则的痛点示例
public class TraditionalBusinessRules {
    
    public void痛点() {
        System.out.println("=== 传统业务规则的痛点 ===");
        System.out.println("1. 代码硬编码:规则写死在代码里");
        System.out.println("2. 变更困难:每次修改都需要重新部署");
        System.out.println("3. 发布风险:频繁上线增加系统风险");
        System.out.println("4. 响应缓慢:无法快速响应业务需求");
        System.out.println("5. 维护成本高:多个版本难以维护");
    }
}

1.2 动态规则引擎的价值

// 动态规则引擎的价值
public class DynamicRuleEngineBenefits {
    
    public void benefits() {
        System.out.println("=== 动态规则引擎的价值 ===");
        System.out.println("1. 业务灵活:规则可动态调整");
        System.out.println("2. 快速响应:无需重新部署即可生效");
        System.out.println("3. 降低风险:减少代码变更和上线频率");
        System.out.println("4. 提升效率:业务人员可自助配置");
        System.out.println("5. 统一管理:集中管理所有业务规则");
    }
}

二、QLExpress简介与优势

QLExpress是阿里巴巴开源的一款轻量级表达式语言,非常适合用来实现动态规则引擎。

2.1 QLExpress特性

// QLExpress特性
public class QLExpressFeatures {
    
    public void features() {
        System.out.println("=== QLExpress特性 ===");
        System.out.println("1. 语法简洁:类似Java语法,易于学习");
        System.out.println("2. 性能优秀:编译后执行,速度快");
        System.out.println("3. 安全可控:沙箱机制,防止恶意代码");
        System.out.println("4. 扩展性强:支持自定义函数和宏");
        System.out.println("5. 易于集成:与SpringBoot无缝集成");
    }
}

2.2 QLExpress与其他规则引擎对比

// QLExpress与其他规则引擎对比
public class RuleEngineComparison {
    
    public void comparison() {
        System.out.println("=== 规则引擎对比 ===");
        System.out.println("Drools:功能强大但复杂,学习成本高");
        System.out.println("QLExpress:轻量级,语法简单,性能好");
        System.out.println("Aviator:表达式引擎,功能相对简单");
        System.out.println("Groovy:功能强大但性能一般,安全性较差");
        System.out.println("推荐:中小型项目选QLExpress,大型复杂项目选Drools");
    }
}

三、SpringBoot集成QLExpress

3.1 依赖配置

<!-- pom.xml 添加依赖 -->
<dependencies>
    <!-- SpringBoot Web Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- QLExpress -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>QLExpress</artifactId>
        <version>3.2.4</version>
    </dependency>
    
    <!-- Redis(用于规则缓存) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    <!-- 数据库(用于规则存储) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <!-- 监控 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

3.2 QLExpress配置类

@Configuration
public class QLExpressConfig {
    
    @Bean
    public ExpressRunner expressRunner() {
        ExpressRunner runner = new ExpressRunner();
        
        // 注册自定义函数
        try {
            runner.addFunction("contains", new ContainsFunction());
            runner.addFunction("startsWith", new StartsWithFunction());
            runner.addFunction("endsWith", new EndsWithFunction());
            runner.addFunction("formatDate", new FormatDateFunction());
        } catch (Exception e) {
            throw new RuntimeException("注册QLExpress函数失败", e);
        }
        
        return runner;
    }
    
    @Bean
    public DefaultContext<String, Object> expressContext() {
        return new DefaultContext<>();
    }
}

3.3 自定义函数实现

// 自定义函数:字符串包含判断
public class ContainsFunction implements InstructionSetFunction {
    
    @Override
    public OperateData callSelf(ExpressionExecutor[] list, 
                              ExpressPackage expressPackage, 
                              RunnerContext context,
                              ErrorInfo errorInfo) throws Exception {
        String source = (String) list[0].getObject(context);
        String target = (String) list[1].getObject(context);
        
        boolean result = source != null && source.contains(target);
        return new OperateData(result, Boolean.class);
    }
}

// 自定义函数:日期格式化
public class FormatDateFunction implements InstructionSetFunction {
    
    @Override
    public OperateData callSelf(ExpressionExecutor[] list, 
                              ExpressPackage expressPackage, 
                              RunnerContext context,
                              ErrorInfo errorInfo) throws Exception {
        Date date = (Date) list[0].getObject(context);
        String pattern = (String) list[1].getObject(context);
        
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        String result = sdf.format(date);
        return new OperateData(result, String.class);
    }
}

四、规则引擎核心实现

4.1 规则实体设计

@Entity
@Table(name = "rule_definitions")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RuleDefinition {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "rule_code", nullable = false, unique = true)
    private String ruleCode; // 规则编码
    
    @Column(name = "rule_name", nullable = false)
    private String ruleName; // 规则名称
    
    @Column(name = "rule_expression", nullable = false, columnDefinition = "text")
    private String ruleExpression; // 规则表达式
    
    @Column(name = "rule_description")
    private String ruleDescription; // 规则描述
    
    @Column(name = "rule_type", nullable = false)
    private String ruleType; // 规则类型(DECISION-决策规则,VALIDATION-校验规则等)
    
    @Column(name = "enabled", nullable = false)
    private Boolean enabled = true; // 是否启用
    
    @Column(name = "priority")
    private Integer priority = 0; // 优先级
    
    @Column(name = "created_at")
    private LocalDateTime createdAt;
    
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;
    
    @PrePersist
    protected void onCreate() {
        createdAt = LocalDateTime.now();
        updatedAt = LocalDateTime.now();
    }
    
    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
    }
}

4.2 规则存储Repository

@Repository
public interface RuleDefinitionRepository extends JpaRepository<RuleDefinition, Long> {
    
    Optional<RuleDefinition> findByRuleCode(String ruleCode);
    
    List<RuleDefinition> findByEnabledTrueOrderByPriorityDesc();
    
    List<RuleDefinition> findByRuleTypeAndEnabledTrue(String ruleType);
}

4.3 规则引擎服务实现

@Service
@Slf4j
public class RuleEngineService {
    
    @Autowired
    private ExpressRunner expressRunner;
    
    @Autowired
    private RuleDefinitionRepository ruleRepository;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final String RULE_CACHE_PREFIX = "rule_engine:rule:";
    private static final long RULE_CACHE_TTL = 300; // 5分钟缓存
    
    /**
     * 执行规则
     */
    public RuleExecutionResult executeRule(String ruleCode, Map<String, Object> context) {
        try {
            // 1. 获取规则定义
            RuleDefinition rule = getRuleDefinition(ruleCode);
            if (rule == null) {
                return RuleExecutionResult.builder()
                        .success(false)
                        .errorCode("RULE_NOT_FOUND")
                        .errorMessage("规则不存在: " + ruleCode)
                        .build();
            }
            
            if (!rule.getEnabled()) {
                return RuleExecutionResult.builder()
                        .success(false)
                        .errorCode("RULE_DISABLED")
                        .errorMessage("规则已禁用: " + ruleCode)
                        .build();
            }
            
            // 2. 执行规则表达式
            Object result = executeExpression(rule.getRuleExpression(), context);
            
            // 3. 返回执行结果
            return RuleExecutionResult.builder()
                    .success(true)
                    .result(result)
                    .ruleCode(ruleCode)
                    .executedAt(LocalDateTime.now())
                    .build();
                    
        } catch (Exception e) {
            log.error("执行规则失败: ruleCode={}", ruleCode, e);
            return RuleExecutionResult.builder()
                    .success(false)
                    .errorCode("EXECUTION_ERROR")
                    .errorMessage("规则执行异常: " + e.getMessage())
                    .build();
        }
    }
    
    /**
     * 批量执行规则
     */
    public List<RuleExecutionResult> executeRules(List<String> ruleCodes, Map<String, Object> context) {
        return ruleCodes.parallelStream()
                .map(ruleCode -> executeRule(ruleCode, context))
                .collect(Collectors.toList());
    }
    
    /**
     * 获取规则定义(带缓存)
     */
    private RuleDefinition getRuleDefinition(String ruleCode) {
        String cacheKey = RULE_CACHE_PREFIX + ruleCode;
        
        // 先从缓存获取
        RuleDefinition cachedRule = (RuleDefinition) redisTemplate.opsForValue().get(cacheKey);
        if (cachedRule != null) {
            return cachedRule;
        }
        
        // 缓存未命中,从数据库获取
        Optional<RuleDefinition> ruleOpt = ruleRepository.findByRuleCode(ruleCode);
        if (ruleOpt.isPresent()) {
            RuleDefinition rule = ruleOpt.get();
            // 存入缓存
            redisTemplate.opsForValue().set(cacheKey, rule, RULE_CACHE_TTL, TimeUnit.SECONDS);
            return rule;
        }
        
        return null;
    }
    
    /**
     * 执行表达式
     */
    private Object executeExpression(String expression, Map<String, Object> context) throws Exception {
        // 创建执行上下文
        DefaultContext<String, Object> expressContext = new DefaultContext<>();
        expressContext.putAll(context);
        
        // 执行表达式
        Object result = expressRunner.execute(expression, expressContext, null, true, false);
        return result;
    }
    
    /**
     * 验证规则语法
     */
    public RuleValidationResult validateRule(String expression) {
        try {
            expressRunner.checkSyntax(expression);
            return RuleValidationResult.builder()
                    .valid(true)
                    .message("规则语法正确")
                    .build();
        } catch (Exception e) {
            return RuleValidationResult.builder()
                    .valid(false)
                    .message("规则语法错误: " + e.getMessage())
                    .build();
        }
    }
    
    /**
     * 清除规则缓存
     */
    public void clearRuleCache(String ruleCode) {
        String cacheKey = RULE_CACHE_PREFIX + ruleCode;
        redisTemplate.delete(cacheKey);
    }
    
    /**
     * 清除所有规则缓存
     */
    public void clearAllRuleCache() {
        Set<String> keys = redisTemplate.keys(RULE_CACHE_PREFIX + "*");
        if (keys != null && !keys.isEmpty()) {
            redisTemplate.delete(keys);
        }
    }
}

4.4 规则执行结果封装

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RuleExecutionResult {
    
    private boolean success;
    private String errorCode;
    private String errorMessage;
    private Object result;
    private String ruleCode;
    private LocalDateTime executedAt;
    private long executionTime; // 执行耗时(毫秒)
}

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RuleValidationResult {
    
    private boolean valid;
    private String message;
    private List<String> errors;
}

五、业务场景实战

5.1 场景一:订单折扣规则

// 订单折扣规则示例
@RestController
@RequestMapping("/api/discount")
@Slf4j
public class DiscountRuleController {
    
    @Autowired
    private RuleEngineService ruleEngineService;
    
    /**
     * 计算订单折扣
     */
    @PostMapping("/calculate")
    public ResponseEntity<DiscountResult> calculateDiscount(@RequestBody OrderRequest request) {
        try {
            // 构造规则执行上下文
            Map<String, Object> context = new HashMap<>();
            context.put("orderAmount", request.getOrderAmount());
            context.put("customerLevel", request.getCustomerLevel());
            context.put("productCategory", request.getProductCategory());
            context.put("orderTime", new Date());
            
            // 执行折扣规则
            RuleExecutionResult result = ruleEngineService.executeRule("DISCOUNT_RULE_001", context);
            
            if (result.isSuccess()) {
                Double discountRate = (Double) result.getResult();
                BigDecimal discountAmount = request.getOrderAmount().multiply(BigDecimal.valueOf(discountRate));
                BigDecimal finalAmount = request.getOrderAmount().subtract(discountAmount);
                
                DiscountResult discountResult = DiscountResult.builder()
                        .originalAmount(request.getOrderAmount())
                        .discountRate(discountRate)
                        .discountAmount(discountAmount)
                        .finalAmount(finalAmount)
                        .build();
                        
                return ResponseEntity.ok(discountResult);
            } else {
                return ResponseEntity.badRequest()
                        .body(DiscountResult.builder()
                                .errorMessage(result.getErrorMessage())
                                .build());
            }
        } catch (Exception e) {
            log.error("计算折扣失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(DiscountResult.builder()
                            .errorMessage("系统异常")
                            .build());
        }
    }
}

// 示例规则表达式(存储在数据库中)
/*
rule_code: DISCOUNT_RULE_001
rule_name: 订单折扣计算规则
rule_expression: 
if (customerLevel == "VIP") {
    if (orderAmount > 1000) {
        return 0.2;  // VIP客户订单金额大于1000元,享受2折
    } else {
        return 0.1;  // VIP客户其他情况,享受1折
    }
} else if (customerLevel == "GOLD") {
    if (orderAmount > 500) {
        return 0.15; // 金牌客户订单金额大于500元,享受1.5折
    } else {
        return 0.05; // 金牌客户其他情况,享受0.5折
    }
} else {
    if (orderAmount > 2000) {
        return 0.1;  // 普通客户订单金额大于2000元,享受1折
    } else {
        return 0.0;  // 普通客户其他情况,无折扣
    }
}
*/

5.2 场景二:风控校验规则

// 风控校验规则示例
@Service
@Slf4j
public class RiskControlService {
    
    @Autowired
    private RuleEngineService ruleEngineService;
    
    /**
     * 风控校验
     */
    public RiskCheckResult checkRisk(TransactionRequest request) {
        try {
            // 构造风控上下文
            Map<String, Object> context = new HashMap<>();
            context.put("userId", request.getUserId());
            context.put("amount", request.getAmount());
            context.put("ipAddress", request.getIpAddress());
            context.put("deviceType", request.getDeviceType());
            context.put("transactionTime", new Date());
            context.put("userRiskScore", getUserRiskScore(request.getUserId()));
            
            // 执行风控规则
            RuleExecutionResult result = ruleEngineService.executeRule("RISK_CONTROL_RULE_001", context);
            
            if (result.isSuccess()) {
                Boolean allowTransaction = (Boolean) result.getResult();
                return RiskCheckResult.builder()
                        .allowed(allowTransaction)
                        .riskLevel(allowTransaction ? "LOW" : "HIGH")
                        .checkTime(LocalDateTime.now())
                        .build();
            } else {
                // 规则执行失败,默认允许交易但记录日志
                log.warn("风控规则执行失败: {}", result.getErrorMessage());
                return RiskCheckResult.builder()
                        .allowed(true)
                        .riskLevel("UNKNOWN")
                        .warningMessage("风控检查异常")
                        .checkTime(LocalDateTime.now())
                        .build();
            }
        } catch (Exception e) {
            log.error("风控校验异常", e);
            // 异常情况下默认允许交易
            return RiskCheckResult.builder()
                    .allowed(true)
                    .riskLevel("SYSTEM_ERROR")
                    .errorMessage("系统异常")
                    .checkTime(LocalDateTime.now())
                    .build();
        }
    }
    
    private double getUserRiskScore(Long userId) {
        // 获取用户风险评分的逻辑
        return 0.5;
    }
}

// 示例风控规则表达式
/*
rule_code: RISK_CONTROL_RULE_001
rule_name: 交易风控校验规则
rule_expression:
// 高风险IP地址检查
def highRiskIps = ["192.168.1.100", "10.0.0.1"];
if (highRiskIps.contains(ipAddress)) {
    return false;  // 高风险IP,拒绝交易
}

// 大额交易检查
if (amount > 10000 && userRiskScore < 0.7) {
    return false;  // 高额交易且用户风险评分较低,拒绝交易
}

// 异常设备检查
if (deviceType == "emulator" || deviceType == "unknown") {
    return false;  // 模拟器或未知设备,拒绝交易
}

// 时间段检查
def hour = formatDate(transactionTime, "HH");
if (hour >= "02" && hour <= "05") {
    // 凌晨2点到5点,增加额外检查
    if (amount > 5000) {
        return false;  // 凌晨大额交易,拒绝
    }
}

return true;  // 通过风控检查
*/

六、规则管理后台

6.1 规则管理Controller

@RestController
@RequestMapping("/api/rules")
@Slf4j
public class RuleManagementController {
    
    @Autowired
    private RuleEngineService ruleEngineService;
    
    @Autowired
    private RuleDefinitionRepository ruleRepository;
    
    /**
     * 查询规则列表
     */
    @GetMapping
    public ResponseEntity<List<RuleDefinition>> listRules(
            @RequestParam(required = false) String ruleType,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {
        
        Pageable pageable = PageRequest.of(page, size, Sort.by("updatedAt").descending());
        
        Page<RuleDefinition> rulePage;
        if (StringUtils.hasText(ruleType)) {
            rulePage = ruleRepository.findByRuleType(ruleType, pageable);
        } else {
            rulePage = ruleRepository.findAll(pageable);
        }
        
        return ResponseEntity.ok(rulePage.getContent());
    }
    
    /**
     * 获取规则详情
     */
    @GetMapping("/{id}")
    public ResponseEntity<RuleDefinition> getRule(@PathVariable Long id) {
        Optional<RuleDefinition> rule = ruleRepository.findById(id);
        return rule.map(ResponseEntity::ok)
                  .orElse(ResponseEntity.notFound().build());
    }
    
    /**
     * 创建规则
     */
    @PostMapping
    public ResponseEntity<RuleDefinition> createRule(@RequestBody RuleDefinition rule) {
        // 验证规则语法
        RuleValidationResult validationResult = ruleEngineService.validateRule(rule.getRuleExpression());
        if (!validationResult.isValid()) {
            throw new IllegalArgumentException("规则语法错误: " + validationResult.getMessage());
        }
        
        rule.setCreatedAt(LocalDateTime.now());
        rule.setUpdatedAt(LocalDateTime.now());
        
        RuleDefinition savedRule = ruleRepository.save(rule);
        
        // 清除相关缓存
        ruleEngineService.clearRuleCache(rule.getRuleCode());
        
        return ResponseEntity.ok(savedRule);
    }
    
    /**
     * 更新规则
     */
    @PutMapping("/{id}")
    public ResponseEntity<RuleDefinition> updateRule(@PathVariable Long id, @RequestBody RuleDefinition rule) {
        Optional<RuleDefinition> existingRule = ruleRepository.findById(id);
        if (!existingRule.isPresent()) {
            return ResponseEntity.notFound().build();
        }
        
        // 验证规则语法
        RuleValidationResult validationResult = ruleEngineService.validateRule(rule.getRuleExpression());
        if (!validationResult.isValid()) {
            throw new IllegalArgumentException("规则语法错误: " + validationResult.getMessage());
        }
        
        RuleDefinition updatedRule = existingRule.get();
        updatedRule.setRuleName(rule.getRuleName());
        updatedRule.setRuleExpression(rule.getRuleExpression());
        updatedRule.setRuleDescription(rule.getRuleDescription());
        updatedRule.setRuleType(rule.getRuleType());
        updatedRule.setEnabled(rule.getEnabled());
        updatedRule.setPriority(rule.getPriority());
        updatedRule.setUpdatedAt(LocalDateTime.now());
        
        RuleDefinition savedRule = ruleRepository.save(updatedRule);
        
        // 清除相关缓存
        ruleEngineService.clearRuleCache(updatedRule.getRuleCode());
        
        return ResponseEntity.ok(savedRule);
    }
    
    /**
     * 删除规则
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteRule(@PathVariable Long id) {
        Optional<RuleDefinition> rule = ruleRepository.findById(id);
        if (rule.isPresent()) {
            ruleRepository.deleteById(id);
            // 清除相关缓存
            ruleEngineService.clearRuleCache(rule.get().getRuleCode());
        }
        return ResponseEntity.ok().build();
    }
    
    /**
     * 测试规则
     */
    @PostMapping("/test")
    public ResponseEntity<RuleExecutionResult> testRule(@RequestBody TestRuleRequest request) {
        RuleExecutionResult result = ruleEngineService.executeRule(request.getRuleCode(), request.getContext());
        return ResponseEntity.ok(result);
    }
    
    /**
     * 验证规则语法
     */
    @PostMapping("/validate")
    public ResponseEntity<RuleValidationResult> validateRule(@RequestBody ValidateRuleRequest request) {
        RuleValidationResult result = ruleEngineService.validateRule(request.getExpression());
        return ResponseEntity.ok(result);
    }
    
    /**
     * 清除所有规则缓存
     */
    @PostMapping("/cache/clear")
    public ResponseEntity<String> clearAllCache() {
        ruleEngineService.clearAllRuleCache();
        return ResponseEntity.ok("缓存清除成功");
    }
}

6.2 规则测试请求对象

@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestRuleRequest {
    
    private String ruleCode;
    private Map<String, Object> context;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ValidateRuleRequest {
    
    private String expression;
}

七、性能优化与监控

7.1 规则执行监控

@Component
@Slf4j
public class RuleExecutionMetrics {
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    private final Counter ruleExecutions;
    private final Counter ruleFailures;
    private final Timer ruleExecutionTimer;
    
    public RuleExecutionMetrics(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        this.ruleExecutions = Counter.builder("rule.engine.executions")
                .description("规则执行次数")
                .register(meterRegistry);
                
        this.ruleFailures = Counter.builder("rule.engine.failures")
                .description("规则执行失败次数")
                .register(meterRegistry);
                
        this.ruleExecutionTimer = Timer.builder("rule.engine.execution.time")
                .description("规则执行耗时")
                .register(meterRegistry);
    }
    
    /**
     * 记录规则执行
     */
    public void recordRuleExecution(String ruleCode, boolean success, long executionTime) {
        ruleExecutions.increment(Tag.of("rule_code", ruleCode), Tag.of("success", String.valueOf(success)));
        
        if (!success) {
            ruleFailures.increment(Tag.of("rule_code", ruleCode));
        }
        
        ruleExecutionTimer.record(executionTime, TimeUnit.MILLISECONDS);
    }
    
    /**
     * 获取规则执行统计
     */
    public RuleExecutionStats getExecutionStats(String ruleCode) {
        // 通过Micrometer获取统计数据
        return new RuleExecutionStats();
    }
}

7.2 规则缓存优化

@Service
public class OptimizedRuleCacheService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    // 使用本地缓存 + Redis缓存的二级缓存策略
    private final Cache<String, RuleDefinition> localCache = 
        Caffeine.newBuilder()
                .maximumSize(1000)
                .expireAfterWrite(60, TimeUnit.SECONDS)
                .build();
    
    /**
     * 获取规则定义(二级缓存)
     */
    public RuleDefinition getRuleDefinition(String ruleCode) {
        // 1. 先查本地缓存
        RuleDefinition rule = localCache.getIfPresent(ruleCode);
        if (rule != null) {
            return rule;
        }
        
        // 2. 查Redis缓存
        String cacheKey = "rule_engine:rule:" + ruleCode;
        rule = (RuleDefinition) redisTemplate.opsForValue().get(cacheKey);
        if (rule != null) {
            localCache.put(ruleCode, rule);
            return rule;
        }
        
        // 3. 查数据库并更新缓存
        // 实现逻辑...
        return null;
    }
}

八、安全与权限控制

8.1 规则编辑权限控制

@RestController
@RequestMapping("/api/rules")
@PreAuthorize("hasRole('ADMIN') or hasRole('RULE_MANAGER')")
public class SecureRuleManagementController {
    
    // 只有管理员或规则管理员才能访问规则管理接口
    
    @PostMapping
    @PreAuthorize("hasAuthority('RULE_CREATE')")
    public ResponseEntity<RuleDefinition> createRule(@RequestBody RuleDefinition rule) {
        // 创建规则需要RULE_CREATE权限
        return ResponseEntity.ok(new RuleDefinition());
    }
    
    @PutMapping("/{id}")
    @PreAuthorize("hasAuthority('RULE_UPDATE')")
    public ResponseEntity<RuleDefinition> updateRule(@PathVariable Long id, @RequestBody RuleDefinition rule) {
        // 更新规则需要RULE_UPDATE权限
        return ResponseEntity.ok(new RuleDefinition());
    }
    
    @DeleteMapping("/{id}")
    @PreAuthorize("hasAuthority('RULE_DELETE')")
    public ResponseEntity<Void> deleteRule(@PathVariable Long id) {
        // 删除规则需要RULE_DELETE权限
        return ResponseEntity.ok().build();
    }
}

8.2 规则表达式安全检查

@Service
public class RuleSecurityValidator {
    
    private static final Set<String> FORBIDDEN_KEYWORDS = Set.of(
        "System", "Runtime", "Process", "File", "Thread", 
        "ClassLoader", "SecurityManager", "exit", "halt"
    );
    
    /**
     * 检查规则表达式安全性
     */
    public boolean isExpressionSafe(String expression) {
        // 检查是否包含禁用关键字
        for (String keyword : FORBIDDEN_KEYWORDS) {
            if (expression.contains(keyword)) {
                return false;
            }
        }
        
        // 检查是否包含危险操作
        if (expression.contains("import ") || 
            expression.contains("new ") || 
            expression.contains("eval(")) {
            return false;
        }
        
        return true;
    }
}

九、最佳实践总结

9.1 规则设计原则

public class RuleDesignPrinciples {
    
    public void principles() {
        System.out.println("=== 规则设计原则 ===");
        System.out.println("1. 简洁性:规则表达式应尽量简单明了");
        System.out.println("2. 可读性:使用有意义的变量名和注释");
        System.out.println("3. 可测试性:规则应易于测试和验证");
        System.out.println("4. 可维护性:避免过于复杂的嵌套逻辑");
        System.out.println("5. 性能考虑:避免在规则中执行耗时操作");
    }
}

9.2 运维操作手册

public class OperationsManual {
    
    public void manual() {
        System.out.println("=== 规则引擎运维手册 ===");
        System.out.println("日常维护:");
        System.out.println("- 监控规则执行成功率和响应时间");
        System.out.println("- 定期清理过期的规则缓存");
        System.out.println("- 备份重要的规则定义");
        System.out.println("- 监控Redis缓存使用情况");
        
        System.out.println("\n应急处理:");
        System.out.println("- 规则执行异常:检查规则语法和上下文");
        System.out.println("- 性能下降:分析慢规则并优化");
        System.out.println("- 缓存失效:手动清除缓存并重启服务");
        System.out.println("- 数据库连接异常:检查数据库连接池配置");
        
        System.out.println("\n版本升级:");
        System.out.println("- 规则语法变更时需要适配");
        System.out.println("- 数据库表结构变更时需要迁移");
        System.out.println("- 缓存策略变更时需要清理旧缓存");
    }
}

结语

通过本文的介绍,相信你已经掌握了如何基于SpringBoot + QLExpress打造一个功能强大的动态规则引擎。这套方案不仅能够满足大多数业务场景的需求,还具有良好的扩展性和维护性。

关键要点总结:

  1. 选择合适的规则引擎:QLExpress轻量级且易用
  2. 合理的架构设计:缓存+数据库的存储方案
  3. 完善的监控体系:性能指标和执行日志
  4. 安全保障机制:权限控制和表达式安全检查
  5. 运维友好性:管理后台和操作手册

记住,规则引擎的价值在于让业务变得更加灵活,但也要注意避免过度设计。在实际应用中,要根据业务复杂度和变更频率来决定是否需要引入规则引擎。

如果你觉得这篇文章对你有帮助,欢迎分享给更多的朋友。在规则引擎的探索路上,我们一起成长!


关注「服务端技术精选」,获取更多干货技术文章!


标题:基于SpringBoot + QLExpress打造动态规则引擎:让业务规则不再束缚代码!
作者:jiangyi
地址:http://www.jiangyi.space/articles/2025/12/21/1766304288922.html

    0 评论
avatar