欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

荐 秒懂java规则表达式框架Aviator2.3.0

程序员文章站 2022-04-11 21:57:42
背景在我们的业务场景中有一个需求,我们有一个配置功能,该功能需要配置两个变量之间比较大小。使用tab比较难表达,所以就提出了,可以让用户写比较简单的函数进行配置。或者选tab进行选择(前段直接将对应的tab字符串拼接来给后端执行)。或者这么说吧,可以通过字符串的表达的意思,进行执行这个字符串的索要表达的逻辑,且这个逻辑和这个字符串可以自定义。Aviator简介Aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。现在已经有很多开源可用的java表达式求...

背景

在我们的业务场景中有一个需求,我们有一个配置功能,该功能需要配置两个变量之间比较大小。使用tab比较难表达,所以就提出了,可以让用户写比较简单的函数进行配置。或者选tab进行选择(前段直接将对应的tab字符串拼接来给后端执行)。

或者这么说吧,可以通过字符串的表达的意思,进行执行这个字符串的索要表达的逻辑,且这个逻辑和这个字符串可以自定义。

Aviator

简介

Aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。现在已经有很多开源可用的java表达式求值引擎,为什么还需要Avaitor呢?

Aviator的设计目标是轻量级和*高性能 ,相比于Groovy、JRuby的笨重,Aviator非常小,加上依赖包也才450K,不算依赖包的话只有70K;当然,Aviator的语法是受限的,它不是一门完整的语言,而只是语言的一小部分集合。

其次,Aviator的实现思路与其他轻量级的求值器很不相同,其他求值器一般都是通过解释的方式运行,而Aviator则是直接将表达式*编译成Java字节码,交给JVM去执行。简单来说,Aviator的定位是介于Groovy这样的重量级脚本语言和IKExpression这样的轻量级表达式引擎之间。

内部原理

  1. 任何语言都是通过一步一步的抽象,从硬件原理再到我们人类可以认识的语言。
  2. Java语言是基于JVM虚拟机抽象上来的语言,通过编译器可以将我们写的代码进行类加载后编译为JVM可以认识的字节码,JVM在进行编译和运行再变为我们操作系统可以运行的代码,直到二极管三极管可以认识的的高低位。
  3. Aviator框架用自己规范最后也编译为JVM虚拟机可以认识的字节码。
    荐
                                                        秒懂java规则表达式框架Aviator2.3.0

基本使用规范

荐
                                                        秒懂java规则表达式框架Aviator2.3.0

官方详细文档:
https://code.google.com/archive/p/aviator/wikis/User_Guide_zh.wiki

  1. 官方文档会讲的很清楚很多细节,在这里不做赘述

代码演示:

1. 需求:前端直接传来一个字符串,通过这个字符串进行相应的逻辑计算。列入A>B 那就是将A>B的计算结果布尔值返回。
package aviator规则引擎;

import com.googlecode.aviator.AviatorEvaluator;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author yuanxindong
 * @date 2020/8/9 12:50
 */
public class AviatorDemo3 {

    public static void main(String[] args) {
        String nameValue = "a";
        String name1Value2 = "b";
        String expression = nameValue + ">" + name1Value2;
        // nameValue
        Object execute = compareAandB(nameValue, name1Value2, expression);
        System.out.println(execute);
    }

    private static Object compareAandB(String A, String B, String expression) {
        Date dateTime = new Date();
        Date dateTime2 = new Date();
        Map<String, Object> map = new HashMap<>(4);
        map.put(A, dateTime);
        map.put(B, dateTime2);
        return AviatorEvaluator.execute(expression, map);
    }

}

需求2. 设计一个根据付款金额决定是否发送优惠券的规则表达式
package aviator规则引擎;

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.AviatorBoolean;
import com.googlecode.aviator.runtime.type.AviatorObject;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * @author yuanxindong
 * @date 2020/8/9 14:28
 */
public class AviatorDemo4 {
    /**
     * 自定义当用户买的商品付款金额大于A价格的时候就认为他啊可以参与抽奖。
     */
    public static void main(String[] args) {
        AviatorEvaluator.addFunction(new IsDiscountFunction());
        Map<String, Object> map = new HashMap(4);
        map.put("discount", new BigDecimal(0.1));
        map.put("price", new BigDecimal(20.0));
        map.put("limit", new BigDecimal(100.00));

        //编译且执行表达式。
        Object isDiscount = AviatorEvaluator.execute("isDiscount(discount,price,limit)", map);
        System.out.println(isDiscount);
    }

    /**
     * 自定义函数
     * 在这里得精度计算
     */
    static class IsDiscountFunction extends AbstractFunction {
        @Override
        public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {
            //arg和对应的map中的value对应
            BigDecimal price = (BigDecimal) FunctionUtils.getNumberValue(arg1, env);
            BigDecimal discount = (BigDecimal) FunctionUtils.getNumberValue(arg2, env);
            BigDecimal limit = (BigDecimal) FunctionUtils.getNumberValue(arg3, env);
            //逻辑
            BigDecimal paymentAmount = price.multiply(discount);
            return AviatorBoolean.valueOf(paymentAmount.compareTo(limit) > -1 ? false : true);
        }

        @Override
        public String getName() {
            return "isDiscount";
        }
    }
}

需求3:

1)设计

业务需求:

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

表达式设计:

“redisCount(‘1’,‘hour’,fields(‘userid,ip,action’)) >= 100”

函数说明:

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

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

package aviator规则引擎;

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;

/**
 * @author yuanxindong
 * @date 2020/8/7 15:15
 */
public class aviatorDemo2 {
    public static void main(String[] args) {
        //注册自定义表达式函数
        AviatorEvaluator.addFunction(new FieldsFunction());
        AviatorEvaluator.addFunction(new RedisCountFunction());

        //函数的重复调用
        String expression = "redisCount('1','hour',fields('userid,ip,action')) >= 10000";
        Expression compiledExp = AviatorEvaluator.compile(expression);

        //运行时收到数据
        Map<String, Object> fields = new HashMap<>(8);
        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";
        }
    }
}

进阶资料: https://tech.meituan.com/2018/04/19/hb-rt-operation.html (规则引擎在美团的应用)

参考资料

官方文档:https://code.google.com/archive/p/aviator/wikis/User_Guide_zh.wiki

http://www.jeepxie.net/article/357848.html

本文地址:https://blog.csdn.net/weixin_40413961/article/details/107896095