于Aviator的规则引擎Demo(转)

编写不易,转载请注明(http://shihlei.iteye.com/blog/2421576)!

一 概述

Aviator 是一个Java 语言实现的表达式引擎,可以接受字符串类型的表达式,带入参数求值。

 

需求场景:

用户日志字段:[ip,phone,userid,action]

 

希望灵活组合这些字段,生成规则,比如 “1小时,userid,在ip上,触发action 100次报警”,并能灵活修改或新增。

 

这种需求基于Avaiator实现非常方便,实现规则引擎后,规则修改组合就不需要研发干预了。

 

本文基于Aviator自定义函数实现一个规则引擎的简单demo,关于读redis计数,报警等非重点仅提供空实现,重在描述思路。

 

依赖:

Xml代码   收藏代码
  1. <dependency>  
  2.     <groupId>com.googlecode.aviator</groupId>  
  3.     <artifactId>aviator</artifactId>  
  4.     <version>3.3.0</version>  
  5. </dependency>  

  

二 简单Demo

(1)带入参数求和:

Java代码   收藏代码
  1. package x.expression.aviator;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import com.googlecode.aviator.AviatorEvaluator;  
  7.   
  8. public class AviatorDemo {  
  9.   
  10.     public static void main(String[] args) {  
  11.         String expression = "a + b + c";  
  12.   
  13.         Map<String, Object> params = new HashMap<>();  
  14.         params.put("a"1);  
  15.         params.put("b"2);  
  16.         params.put("c"3);  
  17.   
  18.         long result = (long) AviatorEvaluator.execute(expression, params);  
  19.   
  20.         System.out.printf("result : " + result);  
  21.     }  
  22. }  

(2)自定义函数:

Aviator 自定义函数,需要实现 com.googlecode.aviator.runtime.type.AviatorFunction , 覆盖想要的方法,然后注册即可使用;

Java代码   收藏代码
  1. package x.expression.aviator;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import com.googlecode.aviator.AviatorEvaluator;  
  7. import com.googlecode.aviator.runtime.function.AbstractFunction;  
  8. import com.googlecode.aviator.runtime.function.FunctionUtils;  
  9. import com.googlecode.aviator.runtime.type.AviatorLong;  
  10. import com.googlecode.aviator.runtime.type.AviatorObject;  
  11.   
  12. public class AviatorSelfFunctionDemo {  
  13.   
  14.     public static void main(String[] args) {  
  15.         //注册函数  
  16.         AviatorEvaluator.addFunction(new MySumFunction());  
  17.   
  18.         String expression = "my_sum(a,b,c)";  
  19.   
  20.         Map<String, Object> params = new HashMap<>();  
  21.         params.put("a"1);  
  22.         params.put("b"2);  
  23.         params.put("c"3);  
  24.   
  25.         long result = (long) AviatorEvaluator.execute(expression, params);  
  26.   
  27.         System.out.printf("result : " + result);  
  28.     }  
  29.   
  30.   
  31.     /** 
  32.      * 自定义函数,实现三元数据求和 
  33.      */  
  34.     static class MySumFunction extends AbstractFunction {  
  35.   
  36.         @Override  
  37.         public AviatorObject call(Map<String, Object> env, AviatorObject a, AviatorObject b, AviatorObject c) {  
  38.             Number numA = FunctionUtils.getNumberValue(a, env);  
  39.             Number numB = FunctionUtils.getNumberValue(b, env);  
  40.             Number numC = FunctionUtils.getNumberValue(c, env);  
  41.   
  42.             long result = numA.longValue() + numB.longValue() + numC.longValue();  
  43.             return new AviatorLong(result);  
  44.         }  
  45.   
  46.         /** 
  47.          * 获取函数名 
  48.          * 
  49.          * @return 函数名 
  50.          */  
  51.         public String getName() {  
  52.             return "my_sum";  
  53.         }  
  54.     }  
  55. }  

 

三 规则引擎

(1)设计

业务需求:

"1小时,userid,在ip上,触发action 100次报警"

表达式设计:

"redisCount('1','hour',fields('userid,ip,action')) >= 100"

函数说明:

fields() : 获取字段,校验,生成redis key

redisCount():使用 key进行查询,获取redis中存的量且redis +1 

 

(2)实现

Java代码   收藏代码
  1. package x.expression.aviator;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import com.googlecode.aviator.AviatorEvaluator;  
  7. import com.googlecode.aviator.Expression;  
  8. import com.googlecode.aviator.runtime.function.AbstractFunction;  
  9. import com.googlecode.aviator.runtime.function.FunctionUtils;  
  10. import com.googlecode.aviator.runtime.type.AviatorLong;  
  11. import com.googlecode.aviator.runtime.type.AviatorObject;  
  12. import com.googlecode.aviator.runtime.type.AviatorString;  
  13.   
  14. public class RuleEngineDemo {  
  15.   
  16.     public static void main(String[] args) {  
  17.         //注册自定义表达式函数  
  18.         AviatorEvaluator.addFunction(new FieldsFunction());  
  19.         AviatorEvaluator.addFunction(new RedisCountFunction());  
  20.   
  21.   
  22.         //用户指定规则  
  23.         String expression = "redisCount('1','hour',fields('userid,ip,action')) >= 100";  
  24.         Expression compiledExp = AviatorEvaluator.compile(expression);  
  25.   
  26.   
  27.         //运行时收到数据  
  28.         Map<String, Object> fields = new HashMap<String, Object>();  
  29.         fields.put("userid""9527");  
  30.         fields.put("ip""127.0.0.1");  
  31.         fields.put("phone""18811223344");  
  32.         fields.put("action""click");  
  33.   
  34.         Boolean needAlarm = (Boolean) compiledExp.execute(fields);  
  35.   
  36.         if (needAlarm) {  
  37.             System.out.printf("报警");  
  38.         }  
  39.     }  
  40.   
  41.   
  42.     static class FieldsFunction extends AbstractFunction {  
  43.   
  44.         @Override  
  45.         public AviatorObject call(Map<String, Object> env, AviatorObject fieldsStrObj) {  
  46.             //获取可变参数  
  47.             String fieldStr = fieldsStrObj.stringValue(env);  
  48.             String[] fields = fieldStr.split(",");  
  49.             StringBuilder redisKey = new StringBuilder();  
  50.   
  51.             System.out.println("FieldsFunction : " + fieldStr);  
  52.   
  53.             for (String f : fields) {  
  54.                 Object value = env.get(f);  
  55.                 if (value != null) {  
  56.                     redisKey.append(value.toString());  
  57.                 } else {  
  58.                     //TODO 参数合法性校验  
  59.                 }  
  60.                 redisKey.append(":");  
  61.             }  
  62.   
  63.             //TODO key 长多过长,会影响redis性能  
  64.             return new AviatorString(redisKey.toString());  
  65.         }  
  66.   
  67.         public String getName() {  
  68.             return "fields";  
  69.         }  
  70.     }  
  71.   
  72.   
  73.     static class RedisCountFunction extends AbstractFunction {  
  74.   
  75.         @Override  
  76.         public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {  
  77.             String period = FunctionUtils.getStringValue(arg1, env);  
  78.             String timeUnit = FunctionUtils.getStringValue(arg2, env);  
  79.             String redisKey = FunctionUtils.getStringValue(arg3, env);  
  80.   
  81.             System.out.println("FieldsFunction : " + period + " , " + timeUnit + " , " + redisKey);  
  82.   
  83.             //TODO 读取redis  
  84.             int redisCount = redisGetAndIncrease(redisKey);  
  85.   
  86.             return new AviatorLong(redisCount);  
  87.         }  
  88.   
  89.         private int redisGetAndIncrease(String redisKey) {  
  90.             System.out.println("get redis : " + redisKey);  
  91.             //这里查询redis获得活动的值;  
  92.             return 10000;  
  93.         }  
  94.   
  95.         public String getName() {  
  96.             return "redisCount";  
  97.         }  
  98.     }  
  99. }  

猜你喜欢

转载自frank1998819.iteye.com/blog/2421897