本文提供了 Evrete(一种新的开源 Java 规则引擎)的首次实践概述。
从历史上看,Evrete被开发为Drools 规则引擎的轻量级替代品 。它完全符合Java 规则引擎规范,并使用经典的前向链 RETE 算法和一些调整和功能来处理大量数据。
它需要 Java 8 及更高版本,零依赖,无缝操作 JSON 和 XML 对象,并允许功能接口作为规则的条件和操作。
它的大部分组件都可以通过服务提供者接口进行扩展,这些 SPI 实现之一将带注释的 Java 类转换为可执行的规则集。我们今天也将尝试一下。
<dependency> <groupId>org.evrete</groupId> <artifactId>evrete-core</artifactId> <version>2.1.04</version> </dependency>
|
要两个规则来处理数据:
- 第一条规则清除每个客户的总销售额
- 第二个规则匹配发票和客户并更新每个客户的总数。
使用流畅的接口声明我们的两个规则:
KnowledgeService service = new KnowledgeService(); Knowledge knowledge = service .newKnowledge() .newRule("Clear total sales") .forEach("$c", Customer.class) .execute(ctx -> { Customer c = ctx.get("$c"); c.setTotal(0.0); }) .newRule("Compute totals") .forEach( "$c", Customer.class, "$i", Invoice.class ) .where("$i.customer == $c") .execute(ctx -> { Customer c = ctx.get("$c"); Invoice i = ctx.get("$i"); c.addToTotal(i.getAmount()); });
|
熟悉 Drools 规则引擎的人会发现我们的规则声明在语义上等同于相同逻辑的以下DRL版本:rule "Clear total sales" when $c: Customer then $c.setTotal(0.0); end
rule "Compute totals" when $c: Customer $i: Invoice(customer == $c) then $c.addToTotal($i.getAmount()); end
|
Evrete的注释版本
<dependency> <groupId>org.evrete</groupId> <artifactId>evrete-dsl-java</artifactId> <version>2.1.04</version> </dependency>
|
使用注释创建与上面相同的规则集:
public class SalesRuleset {
@Rule public void rule1(Customer $c) { $c.setTotal(0.0); }
@Rule @Where("$i.customer == $c") public void rule2(Customer $c, Invoice $i) { $c.addToTotal($i.getAmount()); } }
|
然后我们告诉引擎从外部位置读取我们的规则集定义:
KnowledgeService service = new KnowledgeService(); URL rulesetUrl = new URL("ruleset.java"); // or file.toURI().toURL(), etc Knowledge knowledge = service.newKnowledge( "JAVA-SOURCE", rulesetUrl );
|
每当创建新会话时,引擎会将其与带注释的规则类的新实例耦合。本质上,我们可以将这些类的实例视为会话本身。
因此,如果定义了类变量,则规则方法可以访问这些变量。
如果我们定义条件方法或将新字段声明为方法,这些方法也可以访问类变量。
作为常规 Java 类,此类规则集可以扩展、重用和打包到库中。
官方文档位于https://www.evrete.org/docs/。
代码示例和单元测试可在 GitHub 上获得。