总体:

  • 最后发版为2018年
  • 相比EASY RULE,不支持jexl等脚本语言
  • 支持Spring
  • 内部执行都是使用jdk proxy模式,无论是annotation还是builder模式
  • 可以使用CoRRuleBook 实现chain模式,在chain内按order进行执行
  • 一个rule里面可以有多个action(@Then),多个fact(@Given),多个condition(@When),但注意When只有一个会执行
  • 支持将一个java package的所有rule类组成一个Chain-CoRRuleBook
  • 支持audit

核心概念

Much like the Given-When-Then language for defining tests that was popularized by BDD, RuleBook uses a Given-When-Then language for defining rules. The RuleBook Given-When-Then methods have the following meanings.

  • Given some Fact(s)
  • When a condition evaluates to true
  • Then an action is triggered

核心类及示意代码

rule执行类:GoldenRule

/**
A standard implementation of {@link Rule}.
@param the fact type
@param the Result type
*/
public class GoldenRule<T, U> implements Rule<T, U> {

action 识别代码

public List<Object> getActions() {if (_rule.getActions().size() < 1) {List<Object> actionList = new ArrayList<>();for (Method actionMethod : getAnnotatedMethods(Then.class, _pojoRule.getClass())) {actionMethod.setAccessible(true);Object then = getThenMethodAsBiConsumer(actionMethod).map(Object.class::cast).orElse(getThenMethodAsConsumer(actionMethod).orElse(factMap -> { }));actionList.add(then);}_rule.getActions().addAll(actionList);}return _rule.getActions();
}

condition 设置和获取,可以手工指定condition 如:auditableRule.setCondition(condition);
如果没有设置,使用如下代码识别

@Override
@SuppressWarnings("unchecked")
public Predicate<NameValueReferableMap> getCondition() {//Use what was set by then() first, if it's thereif (_rule.getCondition() != null) {return _rule.getCondition();}//If nothing was explicitly set, then convert the method in the class_rule.setCondition(Arrays.stream(_pojoRule.getClass().getMethods()).filter(method -> method.getReturnType() == boolean.class || method.getReturnType() == Boolean.class).filter(method -> Arrays.stream(method.getDeclaredAnnotations()).anyMatch(When.class::isInstance)).findFirst()

注意findFirst,代表只有一个生效

Chain 管理类 CoRRuleBook 使用Reflections 识别package下所有rule类的核心代码如下:

/*** Gets the POJO Rules to be used by the RuleBook via reflection of the specified package.* @return  a List of POJO Rules*/protected List<Class<?>> getPojoRules() {Reflections reflections = new Reflections(_package);List<Class<?>> rules = reflections.getTypesAnnotatedWith(com.deliveredtechnologies.rulebook.annotation.Rule.class).stream().filter(rule -> _package.equals(rule.getPackage().getName())) // Search only within package, not subpackages.filter(rule -> rule.getAnnotatedSuperclass() != null) // Include classes only, exclude interfaces, etc..collect(Collectors.toList());rules.sort(comparingInt(aClass ->getAnnotation(com.deliveredtechnologies.rulebook.annotation.Rule.class, aClass).order()));return rules;}

Fact管理

/*** A Fact is a single piece of data that can be supplied to a {@link Rule}.* Facts are not immutable; they may be changed by rules and used to derive a result state.*/
public class Fact<T> implements NameValueReferable<T> {private String _name;private T _value;/*** A FactMap decorates {@link Map}; it stores facts by their name and provides convenience methods for* accessing {@link Fact} objects.*/
public class FactMap<T> implements NameValueReferableMap<T> {private Map<String, NameValueReferable<T>> _facts;public FactMap(Map<String, NameValueReferable<T>> facts) {_facts = facts;}

实际上有点key重复的感觉,每个fact 本身还有name和value

Then/action 的执行核心代码 在goldenRule里面

//invoke the actionStream.of(action.getClass().getMethods()).filter(method -> method.getName().equals("accept")).findFirst().ifPresent(method -> {try {method.setAccessible(true);method.invoke(action,ArrayUtils.combine(new Object[]{new TypeConvertibleFactMap<>(usingFacts)},new Object[]{getResult().orElseGet(() -> result)},method.getParameterCount()));if (result.getValue() != null) {_result = result;}} catch (IllegalAccessException | InvocationTargetException err) {LOGGER.error("Error invoking action on " + action.getClass(), err);if (_actionType.equals(ERROR_ON_FAILURE)) {throw err.getCause() == null ? new RuleException(err) :err.getCause() instanceof RuleException ? (RuleException)err.getCause() :new RuleException(err.getCause());}}});facts.putAll(usingFacts);
}

多fact示意

fact 通过@Given进行命名

@Rule
public class HelloWorld {@Given("hello")private String hello;@Given("world")private String world;

然后复制

facts.setValue("hello", "Hello");
facts.setValue("world", "World");

Spring 使用

@Configuration
@ComponentScan("com.example.rulebook.helloworld")
public class SpringConfig {@Bean
public RuleBook ruleBook() {RuleBook ruleBook = new SpringAwareRuleBookRunner("com.example.rulebook.helloworld");
return ruleBook;
}
}

扩展

可以扩展rule类,参考RuleAdapter

public RuleAdapter(Object pojoRule, Rule rule) throws InvalidClassException {com.deliveredtechnologies.rulebook.annotation.Rule ruleAnnotation =getAnnotation(com.deliveredtechnologies.rulebook.annotation.Rule.class, pojoRule.getClass());if (ruleAnnotation == null) {throw new InvalidClassException(pojoRule.getClass() + " is not a Rule; missing @Rule annotation");}_actionType = ruleAnnotation.ruleChainAction();_rule = rule == null ? new GoldenRule(Object.class, _actionType) : rule;_pojoRule = pojoRule;
}

扩展RuleBook(The RuleBook interface for defining objects that handle the behavior of rules chained together.)

/*** Creates a new RuleBookRunner using the specified package and the supplied RuleBook.* @param ruleBookClass the RuleBook type to use as a delegate for the RuleBookRunner.* @param rulePackage   the package to scan for POJO rules.*/public RuleBookRunner(Class<? extends RuleBook> ruleBookClass, String rulePackage) {super(ruleBookClass);_prototypeClass = ruleBookClass;_package = rulePackage;}

当然chain类也可以自己写。

其它

使用predicate的test 来判断condition 来
boolean test(T t)
Evaluates this predicate on the given argument.
Parameters:
t - the input argument
Returns:
true if the input argument matches the predicate, otherwise false

使用isAssignableFrom 来判断输入的fact 是否满足rule类里面的定义
isAssignableFrom是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,默认所有的类的终极父类都是
Object。如果
A.isAssignableFrom(B)结果是true,证明
B可以转换成为
A,也就是
A可以由
B转换而来

rulebook 简单记录相关推荐

  1. python 绘图脚本系列简单记录

    简单记录平时画图用到的python 便捷小脚本 1. 从单个文件输入 绘制坐标系图 #!/usr/bin/python # coding: utf-8 import matplotlib.pyplot ...

  2. ubuntu bind9 配置简单记录

    ubuntu bind9 配置简单记录 ubuntu版本:Ubuntu 12.04.2 bind9安装:apt-get install bind9 bind9配置文件目录:/etc/bind bind ...

  3. 简单记录一下fabric版本1.4的环境搭建,

    简单记录一下fabric版本1.4的环境搭建,运行环境为Ubuntu18.04,其中一些内容是根据官方文档整理的,如有错误欢迎批评指正. 本文只介绍最简单的环境搭建方法,具体的环境搭建解析在这里深入解 ...

  4. oracle 9i 手工建库,简单记录Oracle 9i数据库手工建库过程

    简单记录Oracle 9i数据库手工建库过程Oracle 9i手工建库 By Oracle老菜 今天客户要用oracle 9.2.0.5,aix 6.1已经不支持了,只好从别的数据库把软件拷贝过来重编 ...

  5. mysql signal函数_MySQL:简单记录信号处理

    码版本:5.7.29 简单记录信号如何生效的.poll收到信号后如何中断后如何处理的,需要确认. --- ###一 初始化信号处理方式,设置信号的处理的处理方式,屏蔽某些信号,并且继承到子线程(pth ...

  6. 简单记录双系统安装Ububtu22.04

    简单记录双系统安装Ububtu22.04 tag: #Linux #Ubuntu 双系统安装Ububtu22.04 设备:R9000P 2021 系统:win11 + ubuntu22.04 1.制作 ...

  7. 关于majaro安装后的配置,简单记录 机型华硕FZ53v

    关于majaro安装后的配置,简单记录 机型华硕FZ53v 关于majaro安装后的配置,简单记录 机型华硕FZ53v 关于majaro安装后的配置,简单记录 机型华硕FZ53v ##关于v2ray配 ...

  8. 简单记录下几家公司的面试经历(Java一年经验)

    一年经验,记录下最近几家公司的面试经历. 1.深圳缇铭科技有限公司 1)先让自我介绍,讲一下最近的项目 根据项目提问,比如: redis你是如何部署的?你的code是直接套用他们的模板去编写,还是自己 ...

  9. git版本回退简单记录

    简单记录git版本回退的命令,参考的是这篇文章1 首先查看以前存档的版本: git log 1. 知道要回退的版本和现在的版本差了多少代 回退上一代版本(1个以前) git reset –hard H ...

最新文章

  1. php 类 静态调用 实例化 效率,php类的静态调用和实例化调用有哪些不同点?
  2. mysql key buffer_mysql 开发进阶篇系列 16 MySQL Server(myisam key_buffer)
  3. java 三种错误类型 区别_请列举至少三种在java语言中发生“严重错误”的情况...
  4. “凸优化基础”相关理论知识
  5. SCM供应链管理的背景及意义
  6. uniapp H5页面 点击图片放大预览
  7. Python Scrapy爬虫框架详解
  8. 接入支付宝网页支付的个人记录
  9. 自学Java第二天 解决java不能输出中文问题
  10. 疫情过后第一次线下考试感想
  11. 【其他】kindle电子书脱壳转换格式
  12. 基于Arduino的智能泡茶机(1)——机械系机械创新比赛总结技术点与不足处
  13. word2010去掉回车符
  14. 实现listview条目点击显示和隐藏
  15. Shell脚本实现自动检测/配置/开启/关闭redis后台服务
  16. 知识管理对企业意味着什么
  17. java76-GUL单选按钮和复选按钮
  18. 分布式锁-这一篇全了解(Redis实现分布式锁完美方案)
  19. 牛客网sql练习题解(12-21)
  20. 有趣的自定义view —《聆雨》· 上下滑动面板

热门文章

  1. 服务器不显示ipv4信息,【已经解决】ip addr不显示ipv4
  2. 入门图形学:图像二值化
  3. [C++] [OpenGL] GLFW工具类
  4. 全球最牛的100家AI创企:有多少独角兽?
  5. KBU1010-ASEMI高端适配器扁桥KBU1010
  6. opnet调用matlab引擎
  7. 以叮咚买菜为例,看生鲜电商的春天是否已经到来?
  8. Criteria查询
  9. 动态网页设计(ASP)期末复习总结03 asp六大基本对象
  10. Java调用FFmpeg实现视频录制