编写不易,转载请注明(http://shihlei.iteye.com/blog/2421576)!
一 概述
Aviator 是一个Java 语言实现的表达式引擎,可以接受字符串类型的表达式,带入参数求值。
需求场景:
用户日志字段:[ip,phone,userid,action]
希望灵活组合这些字段,生成规则,比如 “1小时,userid,在ip上,触发action 100次报警”,并能灵活修改或新增。
这种需求基于Avaiator实现非常方便,实现规则引擎后,规则修改组合就不需要研发干预了。
本文基于Aviator自定义函数实现一个规则引擎的简单demo,关于读redis计数,报警等非重点仅提供空实现,重在描述思路。
依赖:
- <dependency>
- <groupId>com.googlecode.aviator</groupId>
- <artifactId>aviator</artifactId>
- <version>3.3.0</version>
- </dependency>
二 简单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";
- Map<String, Object> params = 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)";
- Map<String, Object> params = 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<String, Object> 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);
- //运行时收到数据
- Map<String, Object> fields = new HashMap<String, Object>();
- 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<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";
- }
- }
- 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);
- 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";
- }
- }
- }