Easy Rules:轻量级Java规则引擎在Spring Boot中的集成与应用

内容分享2小时前发布
12 8 0

引言

在日常业务开发中,我们常常会遇到复杂的业务规则判断,例如订单优惠计算、风控决策、审批流程等。如果将所有规则写死在if-else结构中,不仅代码臃肿,还难以维护和扩展。为解决这一问题,规则引擎应运而生。Easy Rules作为一款轻量级的Java规则引擎框架,通过POJO和注解简化了业务规则的管理与执行,特别适合简单业务逻辑处理场景。

Easy Rules:轻量级Java规则引擎在Spring Boot中的集成与应用

Easy Rules核心概念

Easy Rules基于规则引擎的常见原则和概念,其核心组件包括:

  • Rule(规则):规则是Easy Rules框架的核心,定义了业务规则的完整逻辑。
  • Condition(条件):定义规则的前提条件,当条件为true时,规则将被触发。
  • Action(动作):规则触发后执行的代码逻辑。
  • Facts(实际):输入数据的集合,作为规则条件判断的依据。
  • Priority(优先级):定义规则执行的优先顺序。

Easy Rules基础使用示例

以下是一个简单的规则引擎使用示例,用于判断用户是否可以购买酒类产品:

import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Rule;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.core.RulesImpl;
import org.jeasy.rules.core.DefaultRulesEngine;

@Rule(name = "age rule", description = "Check if user is of legal age to buy alcohol")
public class AgeRule {
    @Condition
    public boolean checkAge(@Fact("age") int age) {
        return age >= 18;
    }
    
    @Action
    public void buyAlcohol(Facts facts) {
        System.out.println("User is allowed to buy alcohol");
    }
}

// 使用示例
public class RuleEngineDemo {
    public static void main(String[] args) {
        AgeRule ageRule = new AgeRule();
        Rules rules = new RulesImpl();
        rules.register(ageRule);
        
        DefaultRulesEngine rulesEngine = new DefaultRulesEngine();
        Facts facts = new Facts();
        facts.put("age", 20);
        
        rulesEngine.fire(rules, facts);
    }
}

Easy Rules与Spring Boot集成实践

Easy Rules:轻量级Java规则引擎在Spring Boot中的集成与应用

基础集成

在Spring Boot项目中集成Easy Rules超级简单,只需添加依赖:

<dependency>
    <groupId>org.jeasy</groupId>
    <artifactId>easy-rules-core</artifactId>
    <version>3.0.0</version>
</dependency>

创建规则类并注册到Spring容器中:

import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Priority;
import org.jeasy.rules.annotation.Rule;
import org.jeasy.rules.api.Facts;

@Rule(name = "执行STEP_1", description = "执行第一步处理")
public class Priority100RequestService {
    @Condition
    public boolean condition() {
        return true;
    }

    @Action
    public void action(Facts facts) {
        System.out.println("规则引擎执行STEP_1:开始处理");
        String step1Input = (String) facts.get("STEP_1_INPUT");
        System.out.println("STEP_1入参:" + step1Input);
        // 设置STEP_2的输入参数
        facts.put("STEP_2_INPUT", "来自STEP_1的数据");
        System.out.println("规则引擎执行STEP_1:结束处理");
    }

    @Priority
    public int priority() {
        return 100;
    }
}

创建控制器来触发规则执行:

import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.core.RulesEngineParameters;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/rules")
public class RuleController {
    @GetMapping("/execute")
    public String executeRules() {
        // 创建规则引擎参数
        RulesEngineParameters parameters = new RulesEngineParameters()
                .skipOnFirstAppliedRule(false);
        
        // 创建规则引擎
        RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
        
        // 创建规则集
        Rules rules = new Rules();
        rules.register(new Priority100RequestService());
        rules.register(new Priority101RequestService());
        
        // 创建实际
        Facts facts = new Facts();
        facts.put("STEP_1_INPUT", "初始输入数据");
        
        // 执行规则
        rulesEngine.fire(rules, facts);
        
        // 返回最终结果
        return facts.get("FINAL_OUTPUT").toString();
    }
}

高级集成模式

在实际生产环境中,我们一般需要更灵活的规则管理方式。Easy Rules可以与Spring Boot结合,实现规则的动态加载和配置。

关键组件设计

  1. AdapterRule 接口:所有自定义规则需实现此接口
  2. AutoCreateFactory 工厂类:基于@AutoCreate注解自动扫描和创建规则实例
  3. RefUtils 反射工具类:负责包扫描和类加载

实现步骤

  • 定义规则接口:
public interface AdapterRule {
}
  • 创建带注解的规则实现:
import org.jeasy.rules.annotation.AutoCreate;
import org.jeasy.rules.annotation.Rule;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Priority;
import org.jeasy.rules.api.Facts;

@AutoCreate(value = "MyAppCode", sign = {"STEP_1", "DEFAULT"}, isSingleton = true)
@Rule(name = "执行STEP_1", description = "执行STEP_1")
public class Priority100RequestService implements AdapterRule {
    @Condition
    public boolean condition() {
        return true;
    }

    @Action
    public void action(Facts facts) {
        System.out.println("执行STEP_1:开始");
        String step1Input = (String) facts.get("STEP_1_INPUT");
        System.out.println("STEP_1入参:" + step1Input);
        facts.put("STEP_2_INPUT", "STEP_1出参=STEP_2入参");
        System.out.println("执行STEP_1:结束");
    }

    @Priority
    public int priority() {
        return 100;
    }
}
  • 实现AutoCreateFactory:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
public class AutoCreateFactory {
    private final List<AdapterRule> rules = new ArrayList<>();
    private final Map<String, List<AdapterRule>> ruleMap = new HashMap<>();
    
    @Autowired
    public AutoCreateFactory(List<AdapterRule> allRules) {
        // 按注解属性分类规则
        for (AdapterRule rule : allRules) {
            AutoCreate autoCreate = rule.getClass().getAnnotation(AutoCreate.class);
            if (autoCreate != null) {
                // 根据value分组
                String appCode = autoCreate.value();
                ruleMap.computeIfAbsent(appCode, k -> new ArrayList<>()).add(rule);
                
                // 根据sign分组
                for (String sign : autoCreate.sign()) {
                    ruleMap.computeIfAbsent(sign, k -> new ArrayList<>()).add(rule);
                }
            }
        }
    }
    
    public List<AdapterRule> getRules(String appCode) {
        return ruleMap.getOrDefault(appCode, Collections.emptyList());
    }
    
    public List<AdapterRule> getRulesBySign(String sign) {
        return ruleMap.getOrDefault(sign, Collections.emptyList());
    }
}
  • 在Spring Boot应用中使用:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/rules")
public class RuleController {
    @Autowired
    private AutoCreateFactory autoCreateFactory;
    
    @GetMapping("/execute")
    public String executeRules() {
        // 获取规则
        List<AdapterRule> rules = autoCreateFactory.getRulesBySign("STEP_1");
        
        // 创建规则引擎
        RulesEngineParameters parameters = new RulesEngineParameters()
                .skipOnFirstAppliedRule(false);
        RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
        
        // 创建规则集
        Rules rulesSet = new Rules();
        rules.forEach(rulesSet::register);
        
        // 创建实际
        Facts facts = new Facts();
        facts.put("STEP_1_INPUT", "初始输入数据");
        
        // 执行规则
        rulesEngine.fire(rulesSet, facts);
        
        return facts.get("FINAL_OUTPUT").toString();
    }
}

Easy Rules的优势

  1. 解耦业务逻辑:将业务规则与程序代码解耦,提高系统的灵活性和可维护性
  2. 动态规则加载:支持动态加载和更新规则,无需重启应用
  3. 易于测试和调试:规则独立,便于单元测试和问题排查
  4. 轻量级:无需复杂的配置,与Spring Boot无缝集成
  5. 注解驱动:通过POJO和注解简化规则定义,降低学习成本

适用场景

Easy Rules:轻量级Java规则引擎在Spring Boot中的集成与应用

Easy Rules特别适合以下场景:

  • 简单的业务规则判断(如订单优惠计算、用户等级判断)
  • 需要频繁调整的业务规则(如风控策略、审批流程)
  • 需要快速实现业务决策的场景
  • 作为复杂规则引擎的轻量级替代方案

Easy Rules作为一款轻量级Java规则引擎框架,通过POJO和注解简化了业务规则的管理与执行,特别适合简单业务逻辑处理场景。在Spring Boot项目中集成Easy Rules,可以有效解耦业务逻辑,提高系统的灵活性和可维护性。通过高级集成模式,我们还可以实现规则的动态加载和配置,满足生产环境的实际需求。

© 版权声明

相关文章

8 条评论

  • 头像
    凌晨作案 读者

    我不信最底层,不是if else

    无记录
    回复
  • 头像
    风继续吹 读者

    昨天才刷到liteFlow 今天就来easyRules

    无记录
    回复
  • 头像
    阿偉 读者

    多种规则引擎框架

    无记录
    回复
  • 头像
    学杂馆 读者

    并发bug

    无记录
    回复
  • 头像
    a大方落落a 投稿者

    规则引擎

    无记录
    回复
  • 头像
    要好好生活的HUI 读者

    💗感谢分享

    无记录
    回复
  • 头像
    o一条胖鱼o 投稿者

    真不戳💪

    无记录
    回复
  • 头像
    严宝国 读者

    收藏了,感谢分享

    无记录
    回复