Aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。Aviator相比于Groovy、JRuby的笨重,Aviator非常轻量。
高性能:Aviator 的基本过程是将表达式直接翻译成对应的 java 字节码执行,整个过程最多扫两趟(开启执行优先模式,如果是编译优先模式下就一趟),这样就保证了它的性能超越绝大部分解释性的表达式引擎
轻量级:除了依赖 commons-``beanutils
这个库之外(用于做反射)不依赖任何第三方库,因此整体非常轻量级,整个 jar 包大小哪怕发展到现在 5.0 这个大版本,也才 430K
一些比较有特色的特点:
=~
开放能力:包括自定义函数接入以及各种定制选项
依赖引入
<dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>5.3.3</version>
</dependency>
案例
public class RunScriptExample {
public static void main(String[] args) throws IOException {
// Enable java method invocation by reflection.
AviatorEvaluator.getInstance()
.setFunctionMissing(JavaMethodReflectionFunctionMissing.getInstance());
// You can trry to test every script in examples folder by changing the file name.
Expression exp = AviatorEvaluator.getInstance().compileScript("/Users/10072656/IdeaProjects/spring-demo/src/main/java/com/example/springdemo/examples/hello.av");
exp.execute();
}
}
AviatorScript编译和执行的入口都是AviatorEvaluator
类,该类的一个实例就是一个编译和执行的单元,这个单元我们称为一个 AviatorScript 引擎,AviatorEvaluator.getInstance()
返回一个全局共享的 AviatorScript 引擎。
用 compileScript(path)
方法编译一个脚本文件,这个方法对文件路径查找按照下列顺序:
user.dir
项目的根目录开始的相对路径找到就尝试读取脚本并动态实时地编译成 JVM 字节码,最终的结果是一个 Expression
对象,每次调用 compileScript(path)
都生成一个新的匿名类和对象,因此如果频繁调用会占满 JVM 的 metaspace,可以通过第二个参数决定是否缓冲:
Expression exp = AviatorEvaluator.getInstance().compileScript("examples/hello.av", true);
exp.execute();
如果我们脚步存储在其他地方,比如数据库、外部文件等,获取后得到的是一个String对象,我们可以使用comiple
方法来编译:
Expression compile = AviatorEvaluator.getInstance().compile("println('Hello, AviatorScript!');");
compile.execute();
编译产生的 Expression
对象,最终都是调用 execute()
方法执行,得到结果。但是 execute
方法还可以接受一个变量列表组成的 map,来注入执行的上下文,我们来一个例子:
public class RunAcExample {
public static void main(String[] args) {
String expression = "a + b > 100";
Expression compile = AviatorEvaluator.compile(expression);
Object execute = compile.execute(compile.newEnv("a", 80, "b", 70));
System.out.println(execute);
}
}
我们定义了一个表达式,但是这个表达式的参数具体数值没有指定,我们可以在执行的时候指定具体的数值。
AviatorEvaluator.validate("1 ++ 2");
整数例如 -99、0、1、2、100……等等,对应的类型是 java 中的 long 类型。AviatorScript 中并没有 byte/short/int 等类型,统一整数类型都为 long,支持的范围也跟 java 语言一样。
let a = 99;
let b = 0xFF;
let c = -99;
println(a + b);
println(a / b);
println(a- b + c);
println(a + b * c);
println(a- (b - c));
println(a/b * b + a % b);
public class Number {
public static void main(String[] args) throws IOException {
Expression expression = AviatorEvaluator.getInstance().compileScript("src/main/java/com/example/springdemo/examples/number_demo/number.av");
Object execute = expression.execute();
System.out.println(execute);
}
}
整数相除的结果仍然是整数,比如例子中的
**a/b**
结果就是 0,遵循 java 的整数运算规则。
let a = 10223372036854774807; ## Literal BigInteger
let b = 1000N; ## BigInteger
let c = 1000; ## long type
println(a);
println(a + a);
println(a * a);
println(a + b + c);
数字除了整数之外,AviatorScript 同样支持浮点数,但是仅支持 double 类型,也就是双精度 64 位,符合 IEEE754 规范的浮点数。传入的 java float 也将转换为 double 类型。所有的浮点数都被认为是 double 类型。浮点数的表示形式有两种:
十进制的带小数点的数字,比如 1.34159265
, 0.33333
等等。
科学计数法表示,如 1e-2
, 2E3
等等,大小写字母 e
皆可。
let a = 2;
let err = 1e-15;
let root = a;
while math.abs(a - root * root) &