Aviator-表达式求值引擎

简介
Aviator 是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。现在已经有很多开源可用的java表达式求值引擎,为什么还需要Avaitor呢?
Aviator的设计目标是轻量级和高性能 ,相比于Groovy、JRuby的笨重,Aviator非常小,加上依赖包也才450K,不算依赖包的话只有70K;当然,Aviator的语法是受限的,它不是一门完整的语言,而只是语言的一小部分集合。
其次,Aviator的实现思路与其他轻量级的求值器很不相同,其他求值器一般都是通过解释的方式运行,而Aviator则是直接将表达式编译成Java字节码,交给JVM去执行。简单来说,Aviator的定位是介于Groovy这样的重量级脚本语言和IKExpression这样的轻量级表达式引擎之间。
github地址: https://github.com/killme2008/aviatorscript
推荐看完本文后再到官方文档学习使用:
https://www.yuque.com/boyan-avfmj/aviatorscript/fycwgt
使用
依赖
<dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>{version}</version>
</dependency>
执行表达式
Aviator的使用都是集中通过com.googlecode.aviator.AviatorEvaluator这个入口类来处理,最简单的例子,执行一个计算1+2+3的表达式:
import com.googlecode.aviator.AviatorEvaluator;
public class SimpleExample {
public static void main(String[] args) {
Long result = (Long) AviatorEvaluator.execute("1+2+3");
System.out.println(result); //6
}
}
AviatorEvaluator.execute()可以用直接执行表达式。
细心的朋友肯定注意到结果是Long,而不是Integer。这是因为Aviator的数值类型仅支持Long和Double,任何整数都将转换成Long,任何浮点数都将转换为Double,包括用户传入的变量数值。这个例子的打印结果将是正确答案 6。
使用变量
Expression compiledExp = AviatorEvaluator.compile("max(57,a,b)");
HashMap<String, Object> map = new HashMap<>();
map.put("a", 100);map.put("b", 99);
final Object execute = compiledExp.execute(map);
System.out.println(execute);//100
AviatorEvaluator.compile 编译好表达式,表达式含有未知变量,你可以对一个表达式反复求值。
max() 是自带的函数,用去求 n 个参数中的最大值。
//Expression compiledExp = AviatorEvaluator.compile("你好,我的名称是name");//无法识别表达式报错
//Expression compiledExp = AviatorEvaluator.compile("你好,我的名称是" + "name");//无法识别表达式报错
//Expression compiledExp = AviatorEvaluator.compile("'你好,我的名称是'+ name +'语言'"); 你好,我的名称是java语言
//Expression compiledExp = AviatorEvaluator.compile("'你好,我的名称是'+ name ");//变量前后可以加空格
//Expression compiledExp = AviatorEvaluator.compile("'你好,我的名称是'+name语言");//你好,我的名称是null
Expression compiledExp = AviatorEvaluator.compile("'你好,我的名称是'+name");//你好,我的名称是java
HashMap<String, Object> map = new HashMap<>();
map.put("name", "java");
System.out.println(compiledExp.execute(map));
System.out.println(AviatorEvaluator.execute(" 'a\\\\"b'"));//a"b
System.out.println(AviatorEvaluator.execute(" 'a\\\\\\\\'b'"));//a'b
System.out.println(AviatorEvaluator.execute(" 'hello '+3"));//hello 3
System.out.println(AviatorEvaluator.execute(" 'hello '+ you"));//hello null
上面的例子演示了怎么向表达式传入变量值,表达式中的name是一个变量,默认为null,通过传入Map<String,Object>的变量绑定环境,将name设置为你输入的名称。env的key是变量名,value是变量的值。字符串变量通过 **+变量名
**来标记,中间可以加空格。
Aviator的String是任何用单引号或者双引号括起来的字符序列,String可以比较大小(基于unicode顺序),可以参与正则匹配,可以与任何对象相加,任何对象与String相加结果为String。String中也可以有转义字符,如/n、//、/'等。
自定义函数
import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorBigInt;
import com.googlecode.aviator.runtime.type.AviatorObject;
import java.util.Map;
/**
* ClassName: CustomerIfFunction
* Description: 自定义function
*
* @author systemcaller
* @date 2022/5/25 18:43
**/
public class CustomerIfFunction extends AbstractFunction {
/**
* 计算表达式 CUSTOMER.IF(arg1,arg2,agr3)时
* arg1为真返回arg2,否则返回arg3
*
* @param env
* @param arg1 第一个参数
* @param arg2 第二个参数
* @param arg3 第三个参数
* @return
*/
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {
return FunctionUtils.getBooleanValue(arg1, env)
? new AviatorBigInt(FunctionUtils.getNumberValue(arg2, env))
: new AviatorBigInt(FunctionUtils.getNumberValue(arg3, env));
}
@Override
public String getName() {
return "CUSTOMER.IF";
}
}
public static void main(String[] args) {
//注册函数
AviatorEvaluator.addFunction(new IFFunction());
final Map<String, Object> parmas = Map.of("this", 10000);
System.out.println(AviatorEvaluator.execute("CUSTOMER.IF(this>1000,1,0)",parmas)); //1
}
注册函数通过AviatorEvaluator.addFunction方法,移除可以通过removeFunction。可以添加任意个自定义函数,函数之间可以任意组合。
注意事项
我在时候时遇到过程中遇到了内存占用过大问题,因为我的业务要进行大量的表达式计算,通过查阅官网文档,发现可以采用 编译缓存模式,降低内存占用。