1、依赖:可以只引入core包即可使用规则引擎;
以引入easy-rules-support。支持XOR logic、json描述规则、yaml描述规则。
如果要使用SpEL(Spring Expression Language)、MVEL(表达式解析器)则还需要引入easy-rules-spel[4.1.0开始引入]、easy-rules-mvel
<dependency> <groupId>org.jeasy</groupId> <artifactId>easy-rules-core</artifactId> <version>4.0.0</version> </dependency>API:org.jeasy.rules.api
核心包:org.jeasy.rules.corea) 注解说明(可能解释不够准确,详细参照作者注释)
名称
描述
说明
Action 规则行为注解 只能给无参public修饰符方法使用该注解规则引擎会忽略方法返回值order属性设置规则行为执行顺序Condition 规则条件注解 只能给无参且返回boolean值的公共方法Fact 参数标记设置为fact注解 作为Condition或者Action的参数Priority 规则优先级 只能注解无参并且返回integer值的公共方法Rule将类标记为规则类
属性name:规则注册器内唯一属性description:规则描述属性priority:规则优先级b) 使用举例:
代码示例
说明
@Rule(name = "FactRule", description = "示例",priority = 1) public static class FactRule { @Condition public boolean when(@Fact("fact") Fact fact) { return true; } @Action public void then(@Fact("fact") Fact fact) { //TO DO } }
@Rule注解:注解类FactRule为一个rule。有三个属性:
name:规则名称,必须唯一,同名rule,注册到rules中会被覆盖
descrption:规则描述
priority:执行优先级,注册到rules是会根据priority排序
每个Rule中必须要有一个 @Condition和一个 @Action。
当@Condition注释的方法返回true时,会执行@Action注释的方法;否则,不执行。
a) 函数式接口Action:规则行为接口
void execute(Facts facts) throws Exception:当规则的条件计算为true时执行操作参数:facts不能执行时抛出异常b) 函数式接口Condition:规则条件接口
boolean evaluate(Facts facts):根据已知事实评估情况。c) Rule:可由规则引擎触发的规则的抽象。
d) Facts与Fact:参数
e) RuleListener:用于规则执行事件的侦听器
default boolean beforeEvaluate(Rule rule, Facts facts) :在规则的evaluate前触发,如果rule的condition需要执行返回true,否则返回falsedefault void afterEvaluate(Rule rule, Facts facts, boolean evaluationResult):在规则evaluate后触发default void onEvaluationError(Rule rule, Facts facts, Exception exception):在规则condition的evaluate(求值)过程中发生异常default void beforeExecute(Rule rule, Facts facts):规则execute前触发default void onSuccess(Rule rule, Facts facts):规则execute执行成功default void onFailure(Rule rule, Facts facts, Exception exception):规则execute执行失败f) Rules:封装一组Rule :private Set<Rule> rules = new TreeSet<>(); 感兴趣的可以研究下TreeSet的实现,研究透彻了会对Tree有
g) RulesEngineParameters——【参照引擎DefaultRulesEngine,对引擎参数的使用】
public static final int DEFAULT_RULE_PRIORITY_THRESHOLD:默认优先级阈值, 默认值:Integer.MAX_VALUEprivate boolean skipOnFirstAppliedRule:当一个规则被应用时,跳过下一个适用的规则private boolean skipOnFirstNonTriggeredRule:当一个规则没有被触发时,跳过下一个适用的规则private boolean skipOnFirstFailedRule:当一个规则失败时,跳过下一个适用的规则private int priorityThreshold:优先级超过用户定义的阈值,默认值DEFAULT_RULE_PRIORITY_THRESHOLD。h) RulesEngineListener:在Evaluate之前或者之后,监听每个rules迭代
default void beforeEvaluate(Rules rules, Facts facts)default void afterExecute(Rules rules, Facts facts)i) RulesEngine:规则引擎接口
RulesEngineParameters getParameters():获取规则引擎参数default List<RuleListener> getRuleListeners():获取规则监听器default List<RulesEngineListener> getRulesEngineListeners():获取规则引擎监听器void fire(Rules rules, Facts facts):规则引擎启动default Map<Rule, Boolean> check(Rules rules, Facts facts):启动前检查rulea) abstract class AbstractRulesEngine implements RulesEngine:规则引擎实现,未实现fire和check,跟具体规则引擎有关;如果需要自定义规则引擎,可以继承该类。
b) Easy Rules默认实现规则:
public final class DefaultRulesEngine extends AbstractRulesEngine
说明:
规则是根据它们PRIORITY属性的自然顺序(由小到大)触发的。该实现遍历已排序的规则集,计算每个规则的条件,并在条件为真时执行其操作。实际上是不是根据PRIORITY属性排序,要看Rule实现类的compareTo()的实现;不建议修改。代码关注点:dofire()
Q1、doFire()中直接通过for each迭代rules,如何通过priority控制优先级?----注册时TreeSet();
Q2、RulesEngineParameters属性使用?------根据引擎参数配置跳过规则,如果自己实现引擎的话,需要考虑这些参数的业务,如果不是的话,需要了解默认引擎如何使用该参数
@Override public void fire(Rules rules, Facts facts) { triggerListenersBeforeRules(rules, facts); doFire(rules, facts); triggerListenersAfterRules(rules, facts); } 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; } 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; } } } }public final class InferenceRulesEngine extends AbstractRulesEngine
说明:
基于facts选择rules,并且根据他们priority属性的自然顺序触发这个实现持续地选择和触发规则,直到没有更多的规则可用为止代码关注点:fire()
Q1、引擎实现?---借助DefaultRulesEngine
public InferenceRulesEngine(RulesEngineParameters parameters) { super(parameters); delegate = new DefaultRulesEngine(parameters); } @Override public void fire(Rules rules, Facts facts) { Set<Rule> selectedRules; 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<>(); for (Rule rule : rules) { if (rule.evaluate(facts)) { candidates.add(rule); } } return candidates; }【注意】DefaultRulesEngine和InferenceRulesEngine都是final的,如果不适合,不能继承,只能继承AbstractRulesEngine,并重写。
c) Rule实现:BasicRule与DefaultRule
BasicRule:提供公共方法的基础Rule,可以继承、重写DefaultRule:BasicRule的子类,重写了BasicRule的evaluate、execute;注意该类访问修饰符是默认Q:如何定义rule又不继承Rule或者BasicRule?----- 看RuleProxy实现d) ActionMethodOrderBean:关联操作方法及其执行顺序的实用程序类
e) NoSuchFactException:RuntimeException子类
f) RuleBuilder:Rule实例构建器
g) RuleDefinitionValidator:此组件验证带注解的规则对象是否定义有效
h) RuleProxy:用于从带注解的对象创建规则代理的主类
i) Utils:生成代理类是注解解析工具类