easy-rules mvel yaml 格式规则配置&&试用
网上关于easy-rules 介绍的挺多了,以下是一个学习,以及一些学习说明
demo 说明
demo 是一个简单的用户实体,同时添加了一些帮助方法,对于规则的定义使用yaml 文件(实际上我们可以基于数据库,cache,s3文件系统。。。)
包含了,在实际使用中我么如何修改数据以及mvel 的集成使用,以及一些监听事件的学习
项目准备
- pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dalong</groupId>
<artifactId>myruleapps</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<encoding>UTF-8</encoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-core</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-mvel</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-spel</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
</project>
- 代码结构
├── pom.xml
└── src
└── main
├── java
│ └── com
│ └── dalong
│ ├── Launcher.java
│ ├── User.java
│ └── UserService.java
└── resources
├── rules.yml
└── simplelogger.properties
代码说明
- rules.yml
主要是配置了规则,主要是为了学习参数的传递(class以及map)同时也包含了如何进行参数的修改以及
关于mvel 的集成使用
rules.yml
---
name: "1"
description: "1"
condition: "user.getAge()>26"
priority: 1
actions:
- "user.age=user.age-2;System.out.println(userinfo);"
---
name: "2"
description: "2"
condition: "user.getAge()<26"
priority: 2
actions:
- "UserService.doAction1(user)"
---
name: "3"
description: "3"
condition: "user.name.length<10"
priority: 3
actions:
- "UserService.doAction2(user)"
---
name: "4"
description: "4"
condition: "user.name.length<40"
priority: 4
actions:
- "System.out.println(\"rule4 \"+userinfo)"
---
name: "5"
description: "5"
condition: "user.name.length<30"
priority: 5
actions:
- "UserService.doAction4(userinfo)"
---
name: "6"
description: "6"
condition: "user.name.length<30"
priority: 6
actions:
- "System.out.println(\"rule6 \"+userinfo)"
---
name: "7"
description: "7"
condition: "user.name.length<30"
priority: 7
actions:
- "UserService.doAction4(user)"
---
name: "8"
description: "8"
condition: "user.name.length<30"
priority: 8
actions:
- "System.out.println(\"rule8 \"+user)"
规则简单说明:
总共8个, 主要是基于不同的user 实体以及一个userinfo map 类型数据的处理,包含了如何数据修改
UserService 是一个静态帮助类,主要进行数据操作(更新user以及userinfo 的数据)后边会有代码的说明
- Launcher.java
代码的核心入口
package com.dalong;
import org.jeasy.rules.api.*;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.core.InferenceRulesEngine;
import org.jeasy.rules.core.RuleBuilder;
import org.jeasy.rules.mvel.MVELRuleFactory;
import org.jeasy.rules.support.YamlRuleDefinitionReader;
import org.mvel2.ParserContext;
import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;
import static com.dalong.DecreaseTemperatureAction.decreaseTemperature;
import static com.dalong.HighTemperatureCondition.itIsHot;
import static com.dalong.AppendUserName.appendUserName;
import static com.dalong.NameTooShort.nameTooShort;
public class Launcher {
public static void main(String[] args) throws Exception {
app3();
}
private static void app3() throws Exception {
MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
ParserContext context =new ParserContext();
context.addImport("UserService", UserService.class);
Rules yamlRules = ruleFactory.createRules(new FileReader(Launcher.class.getClassLoader().getResource("rules.yml").getFile()),context);
DefaultRulesEngine rulesEngine = new DefaultRulesEngine();
Facts facts = new Facts();
Map<String,Object> userinfo = new HashMap<>();
userinfo.put("name2","dalong");
userinfo.put("age2",27);
facts.put("user",new User("dalong",27));
facts.put("userinfo",userinfo);
rulesEngine.registerRuleListener(new MyRulesListener());
rulesEngine.registerRulesEngineListener(new MyRuleEngineListener());
rulesEngine.fire(yamlRules, facts);
}
}
因为是使用了mvel 所以使用了MVELRuleFactory,当前因为我们需要依赖一些帮助类操作数据模型,所以导入了UserService
对于数据的传递,我们使用了User 实体模型以及一个map 模型(模拟实际业务场景)
- User.java
用户实体模型,当然可以作为一个简单的pojo处理也行
package com.dalong;
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public User(){
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void dosomeThing() throws Exception {
if(this.age<26){
throw new Exception("age is too small");
}
if(this.name.length()<10){
throw new Exception("some wrong");
}
}
public void setAge(int age) {
this.age = age;
}
}
- UserService.java
主要包含了已给帮助操作类,主要是为了mvel使用,定义了一些action,同时为了学习有一个类型处理的
package com.dalong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.HashMap;
import java.util.Map;
public class UserService {
static Log log = LogFactory.getLog(MyRuleEngineListener.class);
public static void doAction1(User user){
log.info("------------do action1------------");
log.info(user.toString());
}
public static void doAction2(User user){
log.info("------------do action2------------");
user.setName("sssssssssssssssssss");
log.info(user.toString());
}
public static void doAction3(Map user){
log.info("------------do action3------------");
log.info(user.toString());
}
public static void doAction4(Object user){
/**
* 基于mvel 修改数据,为了复用doAction4,做了数据兼容处理
*/
if (user instanceof Map ){
log.info("------------do actionn4------------");
((Map)user).put("name2","rule wwwwwwwwwwwwwwwwww");
}
if (user instanceof User) {
((User)user).setName("dalong demo appapapappapa");
}
log.info(user.toString());
}
}
- MyRulesListener.java
rule 运行的监听,此处我们可以方便进行数据审计记录(存储数据库,同时基于pipline模式,可视化分析任务状态,以及数据)
package com.dalong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.RuleListener;
public class MyRulesListener implements RuleListener {
Log log = LogFactory.getLog(MyRulesListener.class);
@Override
public boolean beforeEvaluate(Rule rule, Facts facts) {
return true;
}
@Override
public void afterEvaluate(Rule rule, Facts facts, boolean b) {
log.info("-----------------afterEvaluate-----------------");
// log.info(rule.getName()+rule.getDescription()+facts.toString());
}
@Override
public void beforeExecute(Rule rule, Facts facts) {
log.info("-----------------beforeExecute-----------------");
// log.info(rule.getName()+rule.getDescription()+facts.toString());
}
@Override
public void onSuccess(Rule rule, Facts facts) {
log.info("-----------------onSuccess-----------------");
// log.info(rule.getName()+rule.getDescription()+facts.toString());
}
@Override
public void onFailure(Rule rule, Facts facts, Exception e) {
log.info("-----------------onFailure-----------------");
log.info(rule.getName()+"----------"+rule.getDescription()+facts.toString()+e.toString());
}
}
- MyRuleEngineListener.java
记录引擎的操作日志
package com.dalong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngineListener;
public class MyRuleEngineListener implements RulesEngineListener {
Log log = LogFactory.getLog(MyRuleEngineListener.class);
@Override
public void beforeEvaluate(Rules rules, Facts facts) {
log.info("-----------------beforeEvaluate-----------------");
log.info(rules.toString() +" "+facts.toString());
}
@Override
public void afterExecute(Rules rules, Facts facts) {
log.info("-----------------afterExecute-----------------");
log.info(rules.toString()+" "+facts.toString());
}
}
一些说明
easy-rules 对于数据的传递是通过map的,所以mvel使用的时候注意key值的处理,同时还有数据类型的处理,一种
比较好的方式是进行类型判断(类似上边的doAction4)
参考资料
https://github.com/j-easy/easy-rules
https://www.theserverside.com/feature/Adding-MVEL-to-the-Java-Developers-Toolkit