Java规则引擎

依赖

<!--规则引擎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";
        }
    }

}

参考资料

  1. Java各种规则引擎
  2. Aviator 表达式求值引擎开源框架
  3. Aviator的规则引擎Demo
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 文/图 胡卓明 春节假期快近尾声,午间和老孔聊起过年的感受。老孔回老家过年,觉得年就是回不去的小时候的回忆。现在真...
    胡卓明阅读 238评论 0 3
  • 尹志平终于进了很多人,一个365,这是个识别率,已经,根本就是放屁,人,到底是怎么样的?他对人开始有些免疫,因为它...
    不像话的故事阅读 165评论 0 0
  • 郭玉华 日项精进打卡【第八天】 一、学习与实践 1.付出不亚于任何人的努力 2.要谦虚不要骄傲 3.要每天反省 4...
    平凡的人生Dian阅读 281评论 0 0