依赖
<!--规则引擎2:Aviator 表达式求值引擎开源框架-->
<dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>3.3.0</version>
</dependency>
示例Demo
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorLong;
import com.googlecode.aviator.runtime.type.AviatorObject;
import com.googlecode.aviator.runtime.type.AviatorString;
import java.util.HashMap;
import java.util.Map;
/**
* 业务需求:
* "1小时,userid,在ip上,触发action 100次则产生报警"
*
* 表达式设计:
* "redisCount('1','hour',fields('userid,ip,action')) >= 100"
*
* 参考资料:https://blog.csdn.net/shihlei/article/details/84919881
*
* 事件报警抽象:
* 需求1:报警判断机制:多长时间内(由时间值和时间单位两个量描述)某个监控对象(允许有多个参数来描述)发生多少次某个事件,则触发一次报警。
*
* 需求2:报警沉默机制:多长时间内,最多触发一次报警。
*
*/
public class RuleEngineDemo {
public static void main(String[] args) {
//默认AviatorEvaluator以编译速度优先:
// AviatorEvaluator.setOptimize(AviatorEvaluator.COMPILE);
//你可以修改为运行速度优先,这会做更多的编译优化:
AviatorEvaluator.setOptimize(AviatorEvaluator.EVAL);
//注册自定义表达式函数
AviatorEvaluator.addFunction(new FieldsFunction());
AviatorEvaluator.addFunction(new RedisCountFunction());
//模拟用户指定规则
// String expression = "(redisCount('1','hour',fields('userid,ip,action')) >= 100)&&(redisCount('1','hour',fields('userid,ip,action')) <= 200)";
String expression = "redisCount('1','hour',fields('userid,ip,action')) <= 100";
Expression compiledExp = AviatorEvaluator.compile(expression);
//模拟运行时收到数据
Map<String, Object> fields = new HashMap<>();
fields.put("userid", "9527");
fields.put("ip", "127.0.0.1");
fields.put("phone", "18811223344");
fields.put("action", "click");
// 报警规则判断
Boolean needAlarm = (Boolean) compiledExp.execute(fields);
if (needAlarm) {
// send alarm message
System.out.printf("发生报警");
}
}
/**
* 获取字段,校验,生成redis key
*/
static class FieldsFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject fieldsStrObj) {
//获取可变参数
String fieldStr = fieldsStrObj.stringValue(env);
String[] fields = fieldStr.split(",");
StringBuilder redisKey = new StringBuilder();
System.out.println("FieldsFunction : " + fieldStr);
for (String f : fields) {
Object value = env.get(f);
if (value != null) {
redisKey.append(value.toString());
} else {
//TODO 参数合法性校验
}
redisKey.append(":");
}
//TODO key如果过长的话,会影响redis的性能
return new AviatorString(redisKey.toString());
}
public String getName() {
return "fields";
}
}
/**
* 使用key进行查询,获取redis中存的量且redis +1
*/
static class RedisCountFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {
String period = FunctionUtils.getStringValue(arg1, env);
String timeUnit = FunctionUtils.getStringValue(arg2, env);//当前支持hour和minutes
String redisKey = FunctionUtils.getStringValue(arg3, env);
System.out.println("FieldsFunction : " + period + " , " + timeUnit + " , " + redisKey);
long expire = getExpireTime(period,timeUnit);
//TODO 读取redis
int redisCount = redisGetAndIncrease(redisKey, expire);
return new AviatorLong(redisCount);
}
/**
* 使用key进行查询,获取redis中存的量且redis +1
* 如果key不存在则
* @param redisKey
* @return
*/
private int redisGetAndIncrease(String redisKey, long expireTime) {
System.out.println("get count from redis : " + redisKey);
// TODO:检查redisKey是否存在,如果不存在则初始化并为其设置超时时间;如果存在则获取redis中存的量且redis +1
//这里模拟查询得到的值
return 300;
}
// 获取超时的秒时间
private long getExpireTime(String period,String timeUnit){
// 模拟一分钟后超时
return 60;
}
public String getName() {
return "redisCount";
}
}
}
参考资料
- Java各种规则引擎
- Aviator 表达式求值引擎开源框架
- Aviator的规则引擎Demo