Java规则引擎drools:drt动态生成规则并附上具体项目逻辑
一 整合
由于本人的码云太多太乱了,于是决定一个一个的整合到一个springboot项目里面。
附上自己的项目地址https://github.com/247292980/spring-boot
以整合功能
spring-boot,FusionChart,thymeleaf,vue,ShardingJdbc,mybatis-generator,微信分享授权,drools,spring-security,spring-jpa,webjars,Aspect
这次就来整合drools的动态生成规则(drt)。
二 开发目的
为什么写规则引擎要做到动态生成规则呢?
因为规则引擎的作用
一些多变的活动逻辑可以再不改变代码,不重新部署系统,如需求改需求,
一些通用但微变的逻辑,如人工智能的机器学习,达到ai修改数据库来微调自己的行为。
以上统称为 决策从逻辑剥离。
真相就是上面的人不放心你,你要根据设计的mysql数据库写一个降智的后台系统给他们来决定什么时候发什么奖品。
三 项目设计
那么,很明显就是开发一个drools的规则引擎和一个有各种说明语言的,对一个数据库的表进行crud的后台操作系统。
drools这里做的很好,后者,drools就有一个workbench来给我们用了,我们还搞了中文版。
但是,什么东西一到了中国,就变味。
中国人看不懂drools的决策表,更不会根据workbench生成决策表。
于是,第一版drool的系统上线了之后,在需求的意见下,我们要搞个降智的后台操作系统。
而正如我之前博客所说,drools的官方文档很强,里面就有drt(动态规则模板)的例子,本质上就是workbench的劣化例子给我们看。
然后,再根据网上各处资源的魔改,我们给规则引擎升级成动态生成规则文件的,这也是我要拿来做例子的
四 代码讲解
我一直是代码即文档的伪支持者,所以大家吧项目clone下来观看更佳。
规则引擎其实就是规则的加载,规则的使用。(动态的规则引擎的规则加载,还要实现规则的生成。)
也就是loadRule和useRule。
loadRule
1.先从数据库获取规则 getActivityRuleList()
2.再跟据获取的规则生成drt可以解析的map型data prepareData(ruleDTO)
3.通过drt解析,生成drl规则string objectDataCompiler.compile(Arrays.asList(data), Thread.currentThread().getContextClassLoader().getResourceAsStream("give-reward-rule-template.drt"));
4.根据以上获得的规则string生成maven结构的规则并加载 createOrRefreshDrlInMemory(ruleDrls)
/**
* 加载规则
*/
public void loadRule() {
try {
List<RuleDTO> ruleDTOs = getActivityRuleList();
log.info("{}条加入规则引擎", ruleDTOs.size());
if (!ruleDTOs.isEmpty()) {
RuleGenerator generator = new RuleGenerator();
generator.generateRules(ruleDTOs);
}
} catch (Exception e) {
log.error("RuleService.loadRule。e={}",e.getMessage(), e);
}
}
/**
* 从数据库里面取规则
*/
public List<RuleDTO> getActivityRuleList() {
Date begin = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
Date end = Date.from(LocalDateTime.now().plusDays(1).atZone(ZoneId.systemDefault()).toInstant()); List<ActivityRule> list = testService.selectAll();
List<RuleDTO> ruleDTOList = new ArrayList<>();
for (ActivityRule dto : list) {
RuleDTO ruleDTO = new RuleDTO();
ruleDTO.setBeginTime(begin);
ruleDTO.setEndTime(end);
ruleDTO.setRule(dto);
ruleDTOList.add(ruleDTO);
}
return ruleDTOList;
}
/**
* 根据传递进来的参数对象生规则
*
* @param ruleDTOs
*/
public void generateRules(List<RuleDTO> ruleDTOs) {
List<String> ruleDrls = new ArrayList<>();
for (int i = 0; i < ruleDTOs.size(); i++) {
//规则的生成
String drlString = applyRuleTemplate(ruleDTOs.get(i));
ruleDrls.add(drlString);
log.info("规则引擎加载规则,id-{}", ruleDTOs.get(i).getRule().getId());
}
//规则的加载
createOrRefreshDrlInMemory(ruleDrls);
}
/**
* 根据Rule生成drl的String
*/
private String applyRuleTemplate(RuleDTO ruleDTO) {
Map<String, Object> data = prepareData(ruleDTO);
// log.info("rule={}", JSON.toJSON(ruleDTO));
ObjectDataCompiler objectDataCompiler = new ObjectDataCompiler();
return objectDataCompiler.compile(Arrays.asList(data), Thread.currentThread().getContextClassLoader().getResourceAsStream("give-reward-rule-template.drt"));
}
/**
* 根据Rule生成drl的map data
*/
protected Map<String, Object> prepareData(RuleDTO ruleDTO) {
Map<String, Object> data = new HashMap<>();
ActivityRule rule = ruleDTO.getRule();
data.put("ruleCode", ruleDTO.hashCode());
data.put("beginTime", DateUtil.dateToStringFormat(ruleDTO.getBeginTime(), "dd-MMM-yyyy"));
data.put("endTime", DateUtil.dateToStringFormat(ruleDTO.getEndTime(), "dd-MMM-yyyy"));
data.put("eventType", FactManager.getFactClassByEvent(rule.getEvent()).getName());
data.put("rule", rule.getRuleValue());
data.put("awardeeType", rule.getAwardeeType());
// data.put("ruleId", rule.getId());
// data.put("joinChannels", ruleDTO.getJoinChannel());
// data.put("priority", rule.getPriority());
// log.info("data={}", JSON.toJSON(data));
return data;
}
/**
* 根据String格式的Drl生成Maven结构的规则
*
* @param rules
*/
private void createOrRefreshDrlInMemory(List<String> rules) {
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
kieFileSystem.generateAndWritePomXML(RuleExecutor.getReleaseId());
for (String str : rules) {
kieFileSystem.write("src/main/resources/" + UUID.randomUUID() + ".drl", str);
log.info("str={}", str);
}
KieBuilder kb = kieServices.newKieBuilder(kieFileSystem).buildAll();
if (kb.getResults().hasMessages(Message.Level.ERROR)) {
log.error("create rule in kieFileSystem Error", kb.getResults());
throw new IllegalArgumentException("生成规则文件失败");
}
doAfterGenerate(kieServices);
}
useRule
1.构建BaseFact buildBaseFact(userId)
2.执行前,对BaseFact,uuid,RegisterMqDTO 进行操作 beforeExecute(orderId, fact, domain)
.根据生成的RegisterFact执行规则匹配,并RuleExecutorResult为执行结果execute(registerFact, orderId)
/**
* 触发规则
*/
public void useRule(String userId, String phone) {
BaseFact fact = buildBaseFact(userId);
/**
* 因为是uuid所以修改了的规则,重载加载是新的drl,故从数据库动态加载之时,is_delete属性要注意
* */
String orderId = UUID.randomUUID().toString();
/**
* 此处应当是从其他服务获取的的消息体,而不是空值
* */
RegisterMqDTO domain = new RegisterMqDTO();
domain.setTelephone(phone);
try {
/*可以知道一条信息,匹配了多少个规则,成功了几个*/
RuleExecutorResult ruleExecutorResult = beforeExecute(orderId, fact, domain);
log.info("RuleService|useRule|ruleExecutorResult={}", JSON.toJSON(ruleExecutorResult));
// Assert.isTrue(ruleExecutorResult.getFailure() == 0, String.format("有%d条规则执行失败", ruleExecutorResult.getFailure()));
} catch (Exception e) {
log.error("RuleService|useRule|class={},orderId={}, userId={}, 规则执行异常:{}", this.getClass().getName(), orderId, "123456789", e.getMessage(), e);
}
}
/**
* 生成初始的baseFact
*/
public BaseFact buildBaseFact(String userId) {
BaseFact fact = new BaseFact();
// 此处应获取用户的信息
// fact.setCust();
fact.setUserId(userId);
return fact;
}
/**
* 执行前
*/
public RuleExecutorResult beforeExecute(String orderId, BaseFact fact, RegisterMqDTO domain) {
RegisterFact registerFact = buildRegisterFact(domain);
CopyUtil.copyPropertiesCglib(fact, registerFact);
log.info("RuleService|beforeExecute|{}事件的orderId={}, RegisterMqDTO={}", registerFact.getClass().getAnnotation(Fact.class).value(), orderId, domain);
return RuleExecutor.execute(registerFact, orderId);
}
/**
* 生成初始的registerFact
*/
private RegisterFact buildRegisterFact(RegisterMqDTO domain) {
RegisterFact registerFact = new RegisterFact(); CopyUtil.copyPropertiesCglib(domain, registerFact);
return registerFact;
}
/**
* modify by xiaohua
* KieBase被抽取
*
* @param fact
* @param orderId
* @return 规则执行结果
* @author xiaohua 2016年10月24日 下午2:09:12
*/
public static RuleExecutorResult execute(BaseFact fact, String orderId) {
LOGGER.info("RuleExecutor|execute|fact={}", JSON.toJSON(fact));
StatelessKieSession statelessKieSession = getKieBase().newStatelessKieSession();
RuleExecuteGlobal global = new RuleExecuteGlobal();
global.setUserId(fact.getUserId());
global.setOrderId(orderId);
global.setFactObj(fact);
global.setResult(new RuleExecutorResult());
statelessKieSession.getGlobals().set("globalParams", global);
statelessKieSession.execute(fact); return global.getResult();
}
五 结尾
其实说难不难,就是这个东西的思路想出来就有点难了。
其中,mq的设计和接入(由于是简单的demo所以也就没有写上),规则执行结果的反馈(虽然是我写的,但是个人感觉有点鸡肋),还有一些项目里面的逻辑,我也只是在demo里面提了几句并没有实现(诸如初始化项目跑一下loadRule的代码,我也没放),但是大致的框架都出来了,我们只要往里面填就可以了。sql语句,配置文件也在项目里面,有兴趣的自己跑跑即可。
Java规则引擎drools:drt动态生成规则并附上具体项目逻辑的更多相关文章
- [Drools]JAVA规则引擎 -- Drools
Drools是一个基于Java的规则引擎,开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的形式存放在文件中,使得规则的变更不需要修正代码重启机器就可以立即在线上环境生效. 本文所使用的de ...
- [Drools]JAVA规则引擎 -- Drools 2
上一篇文章 http://blog.csdn.net/quzishen/archive/2011/01/25/6163012.aspx 描述了一些常用的drools的语法标签和一个模拟实例即发送积分的 ...
- 规则引擎drools封装
一.前言 网上规则引擎drools介绍很多,并且有很多细致的说明,作者也不敢托大说自己的好用,但作者经过2个项目使用过规则引擎后,自己对规则引擎的理解并进行封装,对规则内容及如何使用,有自己的一番实践 ...
- 小明历险记:规则引擎drools教程一
小明是一家互联网公司的软件工程师,他们公司为了吸引新用户经常会搞活动,小明常常为了做活动加班加点很烦躁,这不今天呀又来了一个活动需求,我们大家一起帮他看看. 小明的烦恼 活动规则是根据用户购买订单的金 ...
- 开源规则引擎 drools
java语言开发的开源业务规则引擎 DROOLS(JBOSS RULES )具有一个易于访问企业策略.易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快.效率高.业务分析师或审核人员可以利用 ...
- 开源规则引擎 Drools 学习笔记 之 -- 1 cannot be cast to org.drools.compiler.kie.builder.impl.InternalKieModule
直接进入正题 我们在使用开源规则引擎 Drools 的时候, 启动的时候可能会抛出如下异常: Caused by: java.lang.ClassCastException: cn.com.cheng ...
- JAVA规则引擎 -- Drools
Drools是一个基于java的规则引擎,开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的形式存放在文件中,使得规则的变更不需要修正代码重启机器就可以立即在线上环境生效. 本文所使用的de ...
- 规则引擎 - drools 使用讲解(简单版) - Java
drools规则引擎 项目链接 现状: 运维同学(各种同学)通过后台管理界面直接配置相关规则,这里是通过输入框.下拉框等完成输入的,非常简单: 规则配置完毕后,前端请求后端,此时服务端根据参数(即规则 ...
- 规则引擎drools的简单使用
规则引擎适用于有复杂多变的规则,如商品满减.积分赠送.考勤规则等 一.引入maven依赖 <dependency> <groupId>org.drools</groupI ...
随机推荐
- 编译内核是出现:arch/arm/mm/tlb-v4wbi.S:64:error: too many positional arguments
内核:Linux-3.4.2 编译内核出现arch/arm/mm/tlb-v4wbi.S:64:error: too many positional arguments 交叉工具链太老了,换新一点的. ...
- JavaScript中对象的属性
在JavaScript中,属性决定了一个对象的状态,本文详细的研究了它们是如何工作的. 属性类型 JavaScript中有三种不同类型的属性:命名数据属性(named data properties) ...
- springMVC绑定json参数之二(2.2.3)
二.springmvc 接收不同格式的json字符串 4).格式四:json传递复杂对象(对象中有属性,还有List) 复杂对象: package testVO; import java.util.L ...
- React 特别需要注意的地方
如图:
- 共用体的定义和应用【C++】
定义: 使用覆盖技术,几个变量相互覆盖,从而使几个不同变量共占同一段内存的结构,成为共同体类型的结构. 共同体的定义类似结构体,不过共同体的所有成员都在同一段内存中存放,起始地址一样,并且同一时刻只能 ...
- error C2872: “flann”: 不明确的符号 --- PCL 与OpenCV2 的flann命名空间冲突问题的解决方法
error C2872: "flann": 不明确的符号 - PCL 与OpenCV2命名空间冲突问题的解决方法 error C2872: "flann" 如果 ...
- redis命令集
查看使用运行服务:ping 关闭服务的连接:quit 切换数据库:select index 连接: redis-cli -h -a myPassword 查看密码: config get requir ...
- 聚类算法(二)--BIRCH
BIRCH (balanced iterative reducing and clustering using hierarchies)(名字太长不用管了) 无监督,适合大样本的聚类方法.大多数情况只 ...
- 洛谷P2534 [AHOI2012]铁盘整理
P2534 [AHOI2012]铁盘整理 题目描述 输入输出格式 输入格式: 共两行.第一行为铁盘个数N(1<=N<=50),第二行为N个不同的正整数,分别为从上到下的铁盘的半径R.(1& ...
- 洛谷P1066 2^k进制数
P1066 2^k进制数 题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. ( ...