今天我们介绍另一款规则引擎——rulebook。
其用法跟easyrule有很多相似之处,所以这里就不细讲他的用法了。这篇文章主要讲他与easyrule的差异。
安装:
easyrule文档上提供了两种方式:1 从git源码构建;2 maven。
rulebook文档上提供了三种方式:1 从git源码构建;2 maven;3 gradle。
这个差别不算太大,gradle与maven类似。所以在getting start上,没有太大的区别。
定义规则方式:
都有builder方式,都有pojo的方式。
rulebook和easyrule都可以通过继承重写来自定义自己的rule。rulebook是继承CoRRuleBook,实现的是RuleBook接口。
这里rulebook写了一个注意,定义的rule可以单例使用,不用考虑并发问题,但是事实集不行:
RuleBooks是线程安全的。然而,FactMaps和NameValueReferableMap的其他实现却不是。这意味着RuleBook的单个实例可以使用不同的Facts在不同的线程中运行,而不会产生意外的结果。然而,在不同的线程中使用相同的FactMap可能会导致意想不到的结果。Facts表示RuleBook的单个调用时的数据,而RuleBooks表示可重用的规则集。
通过注解方式定义:二者均支持。RuleBook的基本注解是Given-When-Then。
easyrule支持动态调序;RuleBook不支持,order是@Rule的一个参数。
easyrule提供了一个规则组的概念;rulebook没有。
easyrule的引擎参数全局设置规则调用方式;rulebook使用RuleChainActionType来设置,但不是全局的,而是rule上的。
rulebook在规则创建时用stop()可以判断触发规则后是否继续执行引擎。
//当getCreditScore为500时,因为有stop(),不会触发第二个规则。//credit score under 600 gets a 4x rate increaseaddRule(RuleBuilder.create().withFactType(ApplicantBean.class).withResultType(Double.class) .when(facts -> facts.getOne().getCreditScore() < 600) .then((facts, result) -> result.setValue(result.getValue() * 4)) .stop() .build());//credit score between 600 and 700 pays a 1 point increaseaddRule(RuleBuilder.create().withFactType(ApplicantBean.class).withResultType(Double.class) .when(facts -> facts.getOne().getCreditScore() < 700) .then((facts, result) -> result.setValue(result.getValue() + 1)) .build());
Auditing Rules 规则审计
rulebook有一个特殊的功能,asAuditor(),来启动规则审计。通过使用asAuditor(),RuleBook中的每个规则都可以将自己注册为一个Auditable rule(如果指定了它的名称)。每个添加到RuleBook Auditor的可审计规则在RuleBook中都有其状态记录。当规则在RuleBook中注册为可审计时,它们的RuleStatus为NONE。在运行RuleBook之后,对于所有失败或其条件未评估为true的规则,它们的RuleStatus将被更改为SKIP。对于条件评估为true且then()操作成功完成的规则,其RuleStatus将更改为EXECUTED。这个做多线程异步审计,审批流时,比较有帮助。
将rule定义成spring bean
上面讲了,Rule单例的,所以能够用spring托管。需要引入下面的jar:
<dependency> <groupId>com.deliveredtechnologies</groupId> <artifactId>rulebook-spring</artifactId> <version>0.12</version></dependency>
package com.exampl.rulebook.helloworld.component;@Componentpublic class HelloWorldComponent { public String getHelloWorld(String hello, String world) { return hello + " " + world + "!"; }}
package com.example.rulebook.helloworld;@RuleBean@Rule(order = 1)public class HelloSpringRule { @Given("hello") private String hello; @Result private String result; @When public boolean when() { return hello != null; } @Then public void then() { result = hello; }}
package com.example.rulebook.helloworld;@RuleBean@Rule(order = 2)public class WorldSpringRule { @Autowired HelloWorldComponent helloWorldComponent; @Given("world") private String world; @Result private String result; @When public boolean when() { return world != null; } @Then public void then() { result = helloWorldComponent.getHelloWorld(result, world); }}
@Configuration@ComponentScan("com.example.rulebook.helloworld")public class SpringConfig { @Bean public RuleBook ruleBook() { RuleBook ruleBook = new SpringAwareRuleBookRunner("com.example.rulebook.helloworld"); return ruleBook; }}
@Autowired private RuleBook ruleBook; public void printResult() { NameValueReferableMap<String> facts = new FactMap<>(); facts.setValue("hello", "Hello "); facts.setValue("world", "World"); ruleBook.run(facts); ruleBook.getResult().ifPresent(System.out::println); //prints Hello World! }
这样我们是不是可以在rulebook的规则中使用spring的各种bean了,是不是有点小激动?有了这个功能,似乎刚才与easyrule有差异的那些短板都是毛毛雨啦,哈哈。期待哪位大神把easyrule也弄出来个spring版本。
easyrule跟rulebook没有太大的差异,easyrule的扩展包能支持很多el表达式;rulebook支持了spring托管,带审计功能。具体在项目中如何选用,需要根据不同的需求来考虑了。