总体:
使用方面除了官网的wiki外,推荐阅读
作者:夜尽天明_
链接:https://juejin.cn/post/7048917724126248967
来源:稀土掘金
- 非annotation 方式,执行不是jdk proxy模式
- annotation 方式,和rulebook 类似使用jdk
proxy模式,但由于本质居于pojo和继承模式,proxy调用比较简单,采用return class类指定方法 - 每个rule 只有一个action方法,这点与rulebook不同
- 支持CompositeRule,默认有3种,但不支持rulebook chain式按order执行
- 两种执行引擎,DefaultRulesEngine 只执行一次,InferenceRulesEngine 会循环执行,直到所有rule的evaluation 返回false
- evaluation 相当于rulebook的condition,action相当于rulebook 的then
核心类及代码
public final class DefaultRulesEngine extends AbstractRulesEngine 的执行函数
void doFire(Rules rules, Facts facts) {
if (rules.isEmpty()) {
LOGGER.warn("No rules registered! Nothing to apply");
return;
}
logEngineParameters();
log(rules);
log(facts);
LOGGER.debug("Rules evaluation started");
for (Rule rule : rules) {
final String name = rule.getName();
final int priority = rule.getPriority();
if (priority > parameters.getPriorityThreshold()) {
LOGGER.debug("Rule priority threshold ({}) exceeded at rule '{}' with priority={}, next rules will be skipped",
parameters.getPriorityThreshold(), name, priority);
break;
}
//执行listener ,如果有返回false ,那么就不执行当前rule
if (!shouldBeEvaluated(rule, facts)) {
LOGGER.debug("Rule '{}' has been skipped before being evaluated", name);
continue;
}
boolean evaluationResult = false;
try {
evaluationResult = rule.evaluate(facts);
} catch (RuntimeException exception) {
LOGGER.error("Rule '" + name + "' evaluated with error", exception);
triggerListenersOnEvaluationError(rule, facts, exception);
// give the option to either skip next rules on evaluation error or continue by considering the evaluation error as false
if (parameters.isSkipOnFirstNonTriggeredRule()) {
LOGGER.debug("Next rules will be skipped since parameter skipOnFirstNonTriggeredRule is set");
break;
}
}
if (evaluationResult) {
LOGGER.debug("Rule '{}' triggered", name);
triggerListenersAfterEvaluate(rule, facts, true);
try {
triggerListenersBeforeExecute(rule, facts);
rule.execute(facts);
LOGGER.debug("Rule '{}' performed successfully", name);
triggerListenersOnSuccess(rule, facts);
if (parameters.isSkipOnFirstAppliedRule()) {
LOGGER.debug("Next rules will be skipped since parameter skipOnFirstAppliedRule is set");
break;
}
} catch (Exception exception) {
LOGGER.error("Rule '" + name + "' performed with error", exception);
triggerListenersOnFailure(rule, exception, facts);
if (parameters.isSkipOnFirstFailedRule()) {
LOGGER.debug("Next rules will be skipped since parameter skipOnFirstFailedRule is set");
break;
}
}
} else {
LOGGER.debug("Rule '{}' has been evaluated to false, it has not been executed", name);
triggerListenersAfterEvaluate(rule, facts, false);
if (parameters.isSkipOnFirstNonTriggeredRule()) {
LOGGER.debug("Next rules will be skipped since parameter skipOnFirstNonTriggeredRule is set");
break;
}
}
}
}
private boolean shouldBeEvaluated(Rule rule, Facts facts) {
return triggerListenersBeforeEvaluate(rule, facts);
}
private boolean triggerListenersBeforeEvaluate(Rule rule, Facts facts) {
return ruleListeners.stream().allMatch(ruleListener -> ruleListener.beforeEvaluate(rule, facts));
}
public final class InferenceRulesEngine extends AbstractRulesEngine 循环执行,指定facts结果满足了所有condition都不符合,才停止执行相关rules的核心代码如下:
@Override
public void fire(Rules rules, Facts facts) {
Set<Rule> selectedRules;
//默认只要有selectCandidates(rules, facts) 就会执行,如果facts 没有变化那么selectCandidates返回rules就会一直一样,即不断循环执行
do {
LOGGER.debug("Selecting candidate rules based on the following facts: {}", facts);
selectedRules = selectCandidates(rules, facts);
if (!selectedRules.isEmpty()) {
delegate.fire(new Rules(selectedRules), facts);
} else {
LOGGER.debug("No candidate rules found for facts: {}", facts);
}
} while (!selectedRules.isEmpty());
}
private Set<Rule> selectCandidates(Rules rules, Facts facts) {
Set<Rule> candidates = new TreeSet<>();
//如果facts 没有变化
for (Rule rule : rules) {
if (rule.evaluate(facts)) {
candidates.add(rule);
}
}
return candidates;
}
使用InferenceRulesEngine 一定要修改fact。
UnitRuleGroup 所有rule作为一个整体判断是否执行
@Override
public boolean evaluate(Facts facts) {
if (!rules.isEmpty()) {
for (Rule rule : rules) {
if (!rule.evaluate(facts)) {
return false;
}
}
return true;
}
return false;
}
public class ActivationRuleGroup extends CompositeRule
通过selectedRule来(随机)选择了第一个condition符合的rule
@Override
public boolean evaluate(Facts facts) {
for (Rule rule : rules) {
if (rule.evaluate(facts)) {
selectedRule = rule;
return true;
}
}
return false;
}
public class ConditionalRuleGroup extends CompositeRule 首先判断RuleWithHighestPriority的condition是否满足,如果满足再选择重所有condition符合的rule进行fire
@Override
public boolean evaluate(Facts facts) {
successfulEvaluations = new HashSet<>();
conditionalRule = getRuleWithHighestPriority();
if (conditionalRule.evaluate(facts)) {
for (Rule rule : rules) {
if (rule != conditionalRule && rule.evaluate(facts)) {
successfulEvaluations.add(rule);
}
}
return true;
}
return false;
}
private Rule getRuleWithHighestPriority() {
List<Rule> copy = sort(rules);
// make sure we only have one rule with the highest priority
Rule highest = copy.get(0);
if (copy.size() > 1 && copy.get(1).getPriority() == highest.getPriority()) {
throw new IllegalArgumentException("Only one rule can have highest priority");
}
return highest;
}
RuleGroup支持从yml自动创建,或者手工创建,yml自动创建代码
switch (ruleDefinition.getCompositeRuleType()) {
case "UnitRuleGroup":
compositeRule = new UnitRuleGroup(name);
break;
case "ActivationRuleGroup":
compositeRule = new ActivationRuleGroup(name);
break;
case "ConditionalRuleGroup":
compositeRule = new ConditionalRuleGroup(name);
break;
default:
throw new IllegalArgumentException("Invalid composite rule type, must be one of " + ALLOWED_COMPOSITE_RULE_TYPES);
}
代码创建
public void setUp() {
conditionalRule = new TestRule("conditionalRule", "description0", 0, true);
rule1 = new TestRule("rule1", "description1", 1, true);
rule2 = new TestRule("rule2", "description2", 2, true);
conditionalRuleGroup = new ConditionalRuleGroup();
conditionalRuleGroup.addRule(rule1);
conditionalRuleGroup.addRule(rule2);
conditionalRuleGroup.addRule(conditionalRule);
rules.register(conditionalRuleGroup);
}
从yml文件创建都基于AbstractRuleFactory类
扩展
可以根据需要去扩展AbstractRuleFactory和CompositeRule,依托priority属性实现类似rulebook 的chain 执行