专业的编程技术博客社区

网站首页 > 博客文章 正文

Java规则引擎-easy rules java规则引擎用哪个好

baijin 2024-12-30 01:50:37 博客文章 13 ℃ 0 评论

场景

简单点描述,有点策略模式的味道,所以可以处理if...else...语句;

其核心内容还是在规则引擎,所以和Drools规则类似,目前支持MVEL和SpEL表达式,配置外置;

最后支持各种规则的组合,支持OR和AND等多种规则组合模式。

1、支持facts作为参数判断,解放if...else...语句;

3、支持规则文件外置,释放研发生产力;

2、支持规则组合,实现多业务规则链路执行,短路执行。

功能

  • 轻量级框架,基于API方式
  • 支持基于POJO和注解方式开发
  • 支持创建组合规则
  • 支持使用表达式语言(MVEL/SpEL)

名词描述

  • name:规则名称,唯一性
  • description:说明描述
  • priority:优先级
  • Facts:事实
  • Conditions:条件
  • Actions:执行动作

案例

背景

定义一个业务订单的场景,根据订单类型,执行对应的业务操作。假设,订单类型为两种:普通类型、折扣类型。

普通类型订单:打印日志处理

折扣类型订单:执行折扣计算方法

maven依赖

    <dependency>
      <groupId>org.jeasy</groupId>
      <artifactId>easy-rules-core</artifactId>
      <version>4.0.0</version>
    </dependency>
    <dependency>
      <groupId>org.jeasy</groupId>
      <artifactId>easy-rules-mvel</artifactId>
      <version>4.0.0</version>
    </dependency>
    <dependency>
      <groupId>org.jeasy</groupId>
      <artifactId>easy-rules-spel</artifactId>
      <version>4.0.0</version>
    </dependency>

订单对象

@Data
public class BizOrder {

  /**
   * 商品
   */
  private String goods;

  /**
   * 售价
   */
  private BigDecimal amount;

  /**
   * 订单类型 1、普通类型 2、折扣类型
   */
  private Integer type;

  /**
   * 折扣
   */
  private BigDecimal discount;
}

折扣计算

@Component
@Slf4j
public class OrderService {

  /**
   * 折扣处理方法
   * @param param 参数
   */
  public static void doDiscountAction(Object param) {
    if (param instanceof BizOrder) {
      BizOrder order = ((BizOrder) param);
      log.error("商品goods:{},折后amount:{}", 
                order.getGoods(), order.getAmount().multiply(order.getDiscount()));
    }
  }
}

实现方式

1、基于表达式

步骤

  • 定义事实数据
//定义事实数据
Facts facts = new Facts();
facts.put("type", order.getType());

设置订单类型作为参数。

源码分析

public interface Rule extends Comparable<Rule> {

    String DEFAULT_NAME = "rule";

    String DEFAULT_DESCRIPTION = "description";

    int DEFAULT_PRIORITY = Integer.MAX_VALUE - 1;

    default String getName() {
        return DEFAULT_NAME;
    }

    default String getDescription() {
        return DEFAULT_DESCRIPTION;
    }

    default int getPriority() {
        return DEFAULT_PRIORITY;
    }

    boolean evaluate(Facts facts);
    void execute(Facts facts) throws Exception;

实现了Iterable接口,含有一个Set集合的容器。

  • 表达式分别定义普通类型、折扣类型规则Rule。
Rule ordinaryRule = new RuleBuilder()
        .name("ordinary_order_rule")
        .description("普通订单类型")
        .when(vo -> vo.get("type").equals(1))
        .then(vo -> log.info("这是一个普通订单"))
        .build();

源码分析

public interface Rule extends Comparable<Rule> {

    String DEFAULT_NAME = "rule";

    String DEFAULT_DESCRIPTION = "description";

    int DEFAULT_PRIORITY = Integer.MAX_VALUE - 1;

    default String getName() {
        return DEFAULT_NAME;
    }

    default String getDescription() {
        return DEFAULT_DESCRIPTION;
    }

    default int getPriority() {
        return DEFAULT_PRIORITY;
    }

    boolean evaluate(Facts facts);
    void execute(Facts facts) throws Exception;

很明显是Comparable的一个子类,方法evaluate()返回boolean是否加载了规则,以及execute()执行规则动作。

  • 注册规则
//注册
Rules rules = new Rules();
rules.register(activationRuleGroup);
  • 启动点火
 //启动点火
 RulesEngine rulesEngine = new DefaultRulesEngine();
 rulesEngine.fire(rules, facts);

采用了默认的规则引擎


整体代码实现

  @AuthIgnore
  @OperationLog(value = "easy rules 表达式测试")
  @PostMapping("/stream")
  @SneakyThrows
  public ResultVo<?> streamTest(@RequestBody BizOrder order) {
    //定义事实数据
    Facts facts = new Facts();
    facts.put("type", order.getType());
    ActivationRuleGroup activationRuleGroup = new ActivationRuleGroup("order_type_rule","订单类型规则");
    //普通类型
    Rule ordinaryRule = new RuleBuilder()
        .name("ordinary_order_rule")
        .description("普通订单类型")
        .when(vo -> vo.get("type").equals(1))
        .then(vo -> log.info("这是一个普通订单"))
        .build();
    activationRuleGroup.addRule(ordinaryRule);
   //折扣类型
    Rule discountRule = new RuleBuilder()
        .name("discount_order_rule")
        .description("折扣订单类型")
        .when(vo -> vo.get("type").equals(2))
        .then(vo -> {
          log.info("这是一个折扣订单");
          //执行其他逻辑
          OrderService.doDiscountAction(order);
        })
        .build();
    activationRuleGroup.addRule(discountRule);
    //注册
    Rules rules = new Rules();
    rules.register(activationRuleGroup);
    //启动点火
    RulesEngine rulesEngine = new DefaultRulesEngine();
    rulesEngine.fire(rules, facts);
    return ResultVo.success();
  }

调试

请求参数


输出日志



我们也可以从日志中看出规则引擎加载的参数,规则注册,以及facts的赋值,


2、基于注解

分别定义两个规则POJO

普通类型订单

@Rule(name = "ordinary_order_rule", description = "普通订单类型", priority = 1)
@Slf4j
public class OrdinaryOrderRule {

  @Condition
  public boolean when(@Fact("order") BizOrder order) {
    return Objects.equals(order.getType(), 1);
  }

  @Action
  public void action(@Fact("order") BizOrder order) {
    log.info("这是一个普通订单,商品goods:{}", order.getGoods());
  }
}

折扣类型订单

@Rule(name = "discount_order_rule", description = "折扣订单类型",priority =2)
@Slf4j
public class DiscountOrderRule {

  @Condition
  public boolean when(@Fact("order")BizOrder order) {
    return Objects.equals(order.getType(),2);
  }

  @Action(order = 1)
  public void action(@Fact("order")BizOrder order) {
    log.info("这是一个折扣订单,商品goods:{}",order.getGoods());
  }

  @Action(order = 2)
  public void action2(@Fact("order")BizOrder order) {
    //调用其他业务处理
    OrderService.doDiscountAction(order);
  }
}

接口处理

	@AuthIgnore
  @OperationLog(value = "easy rules 注解测试")
  @PostMapping("/annotation")
  @SneakyThrows
  public ResultVo<?> annotationTest(@RequestBody BizOrder order) {
    //定义数据
    Facts facts = new Facts();
    facts.put("order", order);
    ActivationRuleGroup activationRuleGroup = new ActivationRuleGroup("order_type_rule","订单类型规则");
    activationRuleGroup.addRule(new OrdinaryOrderRule());
    activationRuleGroup.addRule(new DiscountOrderRule());
    //注册
    Rules rules = new Rules();
    rules.register(activationRuleGroup);
    //启动点火
    RulesEngine rulesEngine = new DefaultRulesEngine();
    rulesEngine.fire(rules, facts);
    return ResultVo.success();
  }

3、基于配置文件

可以是json(本文),也可以是yml,当然也可以结合Apollo。

定义json文件,biz_order_rule.json

[
  {
    "name":"order_type_rule",
    "description":"订单类型规则引擎",
    "priority":1,
    "compositeRuleType":"ActivationRuleGroup",
    "composingRules":[
      {
        "name":"ordinary_order_rule",
        "description":"普通订单类型",
        "condition":"param.getType().equals(1)",
        "priority":1,
        "actions":[
          "System.out.println(\"这是一个普通订单\")"
        ]
      },
      {
        "name":"discount_order_rule",
        "description":"折扣类型规则",
        "condition":"param.getType().equals(2)",
        "priority":2,
        "actions":[
          "OrderService.doDiscountAction(param)"
        ]
      }
    ]
  }
]

构建rules配置

@Component
public class ConfigRules {

  /**
   * 构建rules配置
   */
  public Rules fetchConfigRules() throws Exception {
    //JSON 表达式
    MVELRuleFactory ruleFactory = new MVELRuleFactory(new JsonRuleDefinitionReader());
    return ruleFactory.createRules(new FileReader(
      Objects.requireNonNull(SpringBootApplication.class.getClassLoader().getResource("biz_order_rule.json"))
      .getFile())
                                );
  }
}

API逻辑处理

 @AuthIgnore
  @OperationLog(value = "easy rules 配置文件测试")
  @PostMapping("/json")
  @SneakyThrows
  public ResultVo<?> jsonTest(@RequestBody BizOrder order) {
    //定义数据
    Facts facts = new Facts();
    facts.put("param", order);
    facts.put("OrderService",OrderService.class);
    //读取配置
    Rules rules = configRules.fetchConfigRules();
    BizRule<BizOrder> rule = new BizRule<>();
    //注册
    rules.register(rule);
    //启动
    RulesEngine rulesEngine = new DefaultRulesEngine();
    rulesEngine.fire(rules, facts);
    return ResultVo.success();
  }

参考官方文档:https://github.com/j-easy/easy-rules/wiki

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表