编写不易,转载请注明(http://shihlei.iteye.com/blog/2421576)!
一 概述
Aviator 是一个Java 语言实现的表达式引擎,可以接受字符串类型的表达式,带入参数求值。
需求场景:
用户日志字段:[ip,phone,userid,action]
希望灵活组合这些字段,生成规则,比如 “1小时,userid,在ip上,触发action 100次报警”,并能灵活修改或新增。
这种需求基于Avaiator实现非常方便,实现规则引擎后,规则修改组合就不需要研发干预了。
本文基于Aviator自定义函数实现一个规则引擎的简单demo,关于读redis计数,报警等非重点仅提供空实现,重在描述思路。
依赖:
com.googlecode.aviator aviator 3.3.0
二 简单Demo
(1)带入参数求和:
package x.expression.aviator; import java.util.HashMap; import java.util.Map; import com.googlecode.aviator.AviatorEvaluator; public class AviatorDemo { public static void main(String[] args) { String expression = "a + b + c"; Mapparams = new HashMap<>(); params.put("a", 1); params.put("b", 2); params.put("c", 3); long result = (long) AviatorEvaluator.execute(expression, params); System.out.printf("result : " + result); } }
(2)自定义函数:
Aviator 自定义函数,需要实现 com.googlecode.aviator.runtime.type.AviatorFunction , 覆盖想要的方法,然后注册即可使用;
package x.expression.aviator; import java.util.HashMap; import java.util.Map; import com.googlecode.aviator.AviatorEvaluator; 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; public class AviatorSelfFunctionDemo { public static void main(String[] args) { //注册函数 AviatorEvaluator.addFunction(new MySumFunction()); String expression = "my_sum(a,b,c)"; Mapparams = new HashMap<>(); params.put("a", 1); params.put("b", 2); params.put("c", 3); long result = (long) AviatorEvaluator.execute(expression, params); System.out.printf("result : " + result); } /** * 自定义函数,实现三元数据求和 */ static class MySumFunction extends AbstractFunction { @Override public AviatorObject call(Map env, AviatorObject a, AviatorObject b, AviatorObject c) { Number numA = FunctionUtils.getNumberValue(a, env); Number numB = FunctionUtils.getNumberValue(b, env); Number numC = FunctionUtils.getNumberValue(c, env); long result = numA.longValue() + numB.longValue() + numC.longValue(); return new AviatorLong(result); } /** * 获取函数名 * * @return 函数名 */ public String getName() { return "my_sum"; } } }
三 规则引擎
(1)设计
业务需求:
"1小时,userid,在ip上,触发action 100次报警"
表达式设计:
"redisCount('1','hour',fields('userid,ip,action')) >= 100"
函数说明:
fields() : 获取字段,校验,生成redis key
redisCount():使用 key进行查询,获取redis中存的量且redis +1
(2)实现
package x.expression.aviator; import java.util.HashMap; import java.util.Map; 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; public class RuleEngineDemo { public static void main(String[] args) { //注册自定义表达式函数 AviatorEvaluator.addFunction(new FieldsFunction()); AviatorEvaluator.addFunction(new RedisCountFunction()); //用户指定规则 String expression = "redisCount('1','hour',fields('userid,ip,action')) >= 100"; Expression compiledExp = AviatorEvaluator.compile(expression); //运行时收到数据 Mapfields = 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) { System.out.printf("报警"); } } static class FieldsFunction extends AbstractFunction { @Override public AviatorObject call(Map 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"; } } static class RedisCountFunction extends AbstractFunction { @Override public AviatorObject call(Map env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) { String period = FunctionUtils.getStringValue(arg1, env); String timeUnit = FunctionUtils.getStringValue(arg2, env); String redisKey = FunctionUtils.getStringValue(arg3, env); System.out.println("FieldsFunction : " + period + " , " + timeUnit + " , " + redisKey); //TODO 读取redis int redisCount = redisGetAndIncrease(redisKey); return new AviatorLong(redisCount); } private int redisGetAndIncrease(String redisKey) { System.out.println("get redis : " + redisKey); //这里查询redis获得活动的值; return 10000; } public String getName() { return "redisCount"; } } }