Aviator执行引擎学习整理

  • 高性能
  • 轻量级
  • Java语言实现
  • 表达式求值引擎
  • 用于各种表达式的动态求值
为什么选择aviator?
  1. 设计目标就是轻量级和高性能,相比于Groovy和JRuby的笨重,aviator非常小
  2. 其他求值器一般是通过解释的方式运行,而aviator是直接将表达式编译成Java字节码,交给JVM去执行
  3. 支持大部分运算操作符【算数操作符、关系运算符、逻辑操作符、位运算、正则匹配操作符=~、三元运算符】,并且支持操作符的优先级和括号强制优先级
缺点

语法受限,不是一门完整的语言,只是语言的一小部分集合。

依赖
<dependency>
    <groupId>com.googlecode.aviator</groupId>
    <artifactId>aviator</artifactId>
    <version>2.3.3</version>
</dependency>
执行表达式
public static void main(String[] args) {
    Long execute = (Long) AviatorEvaluator.execute("1+2+3");
    System.out.println(execute);
}

这里的结果类型为long,而不是integer。因为aviator支持的数值类型仅有Long和Double

变量使用
public static void main(String[] args) {
    String name = "aaa";
    Map<String, Object> env = new HashMap<String, Object>(10);
    env.put("name", name);
    String execute = (String) AviatorEvaluator.execute("'hello '+ name", env);
    System.out.println(execute);
}

结果:hello aaa

上述,name为一个变量,默认为null,通过传入env的变量绑定环境,将name设置为输入的名称。

env的key为变量名,value是变量的值。

  1. Aviator的String是任何用单引号或双引号括起来的字符序列。
  2. String可以比较大小(基于Unicode顺序)
  3. 可以参与正则匹配
  4. 可以与任何对象相加,相加结果为String
  5. String中的转义字符:\n、\\、\'
AviatorEvaluator.execute(" 'a\"b' ");           // 字符串 a"b
AviatorEvaluator.execute(" \"a\'b\" ");         // 字符串 a'b
AviatorEvaluator.execute(" 'hello ' + 3 ");     // 字符串 hello 3
AviatorEvaluator.execute(" 'hello '+ unknow "); // 字符串 hello null
exec方法

Aviator2.2开始新增了exec方法,可以更加方便的传入变量并执行,而不需要构造env这个Map了

public static void main(String[] args) {
    String name = "aaa";
    String exec = (String) AviatorEvaluator.exec("'hello ' + name", name);
    System.out.println(exec);
}

只需要在exec方法中按照变量在表达式中的出现顺序传入变量值就可执行,不需要构建map了

调用函数

Aviator支持函数调用,函数调用的风格类似lua

public static void main(String[] args) {
    Long execute = (Long) AviatorEvaluator.execute("string.length('hello')");
    System.out.println(execute);
}

执行结果:5

string.length(hello):获取字符串长度

string.substring(字符串,index,end):截取字符串

string.contains():是否包含

自定义函数

自定义函数需要实现com.googlecode.aviator.runtime.type.AviatorFunction接口,并注册到AviatorEvaluator即可使用

package com.ly;

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

import java.util.Map;

/**
 * @author LY
 * @Description 自定义函数
 */
public class demo05 {
    public static void main(String[] args) {
        // 注册函数
        AviatorEvaluator.addFunction(new AddFunction());
        System.out.println(AviatorEvaluator.execute("add(1, 2)"));
        System.out.println(AviatorEvaluator.execute("add(add(1, 2), 100)"));
    }
}

/**
 * 自定义函数
 */
class AddFunction extends AbstractFunction{
    @Override
    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
        Number number1 = FunctionUtils.getNumberValue(arg1, env);
        Number number2 = FunctionUtils.getNumberValue(arg2, env);
        return new AviatorDouble(number1.doubleValue() + number2.doubleValue());
    }

    public String getName() {
        return "add";
    }
}

执行结果:

3.0
103.0

编译表达式
public static void main(String[] args) {
    String expression = "a - b + c * d";
    Expression compile = AviatorEvaluator.compile(expression);
    Map<String, Object> env = new HashMap<String, Object>();
    env.put("a", 1);
    env.put("b", 2);
    env.put("c", 3);
    env.put("d", 4);
    Long execute = (Long) compile.execute(env);
    System.out.println(execute);
}

通过compile方法将表达式编译成Expression中的中间对象,当要执行表达式时传入env并调用Expression的execute方法即可。

表达式中可使用括号来强制优先级

表达式编译后的结果可以自己缓存,也可交给Aviator来帮助缓存。AviatorExecutor内部有一个全局的缓存池。

通过:public static Expression compile(String expression, boolean cached),将cached设置为true则下次编译同一个表达式时将直接返回上一次编译的结果。

使用public static void invalidateCache(String expression)使缓存失效。

访问数组和集合

可以通过中括号访问数组和java.util.List对象

通过map.key访问java.util.Map中key对应的value

public static void main(String[] args) { 
    final List<String> list = new ArrayList<String>();
    list.add("hello");
    list.add(" world");
    final int[] array = new int[3];
    array[0] = 0;
    array[1] = 1;
    array[2] = 3;
    final Map<String, Date> map = new HashMap<String, Date>();
    map.put("date", new Date());
    Map<String, Object> env = new HashMap<String, Object>();
    env.put("list", list);
    env.put("array", array);
    env.put("mmap", map);
    System.out.println(AviatorEvaluator.execute("list[0]+list[1]", env));   // hello world
    System.out.println(AviatorEvaluator.execute("'array[0]+array[1]+array[2]=' + (array[0]+array[1]+array[2])", env));  // array[0]+array[1]+array[2]=4
    System.out.println(AviatorEvaluator.execute("'today is ' + mmap.date ", env));  // today is Wed Feb 24 17:31:45 CST 2016
}
三元运算

Aviator中没有if else语句

public static void main(String[] args) {
    System.out.println(AviatorEvaluator.exec("a>1?'yes':'no'", 2));
}

yes和no为字符串,需要加引号

public static void main(String[] args) {
    System.out.println(AviatorEvaluator.exec("a>1?a * 2:a - 1", 2));
}

结果可进行运算

两分支结果可以是不同类型的

正则表达式匹配

支持Ruby和Perl风格的表达式匹配运算,通过=~操作符

public static void main(String[] args) { 
    String email = "killme2008@gmail.com";
    Map<String, Object> env = new HashMap<String, Object>();
    env.put("email", email);
    String username = (String) AviatorEvaluator.execute("email=~/([\\w0-8]+)@\\w+[\\.\\w+]+/ ? $1 : 'unknow' ", env);
    System.out.println(username); // killme2008
}

Aviator的正则表达式规则跟Java完全一样,其内部使用的就是java.util.regex.Pattern做编译

变量的语法糖

当要访问变量a中的某个属性b时,可以通过使用a.b访问到。更深:a.b.c

即Aviator可以将变量声明为嵌套访问的形式

public class TestAviator { 
    int i;
    float f;
    Date date;
    // 构造方法
    public TestAviator(int i, float f, Date date) { 
        this.i = i;
        this.f = f;
        this.date = date;
    }
    // getter and setter

    public static void main(String[] args) { 
        TestAviator foo = new TestAviator(100, 3.14f, new Date());
        Map<String, Object> env = new HashMap<String, Object>();
        env.put("foo", foo);
        System.out.println(AviatorEvaluator.execute("'foo.i = '+foo.i", env));   // foo.i = 100
        System.out.println(AviatorEvaluator.execute("'foo.f = '+foo.f", env));   // foo.f = 3.14
        System.out.println(AviatorEvaluator.execute("'foo.date.year = '+(foo.date.year+1990)", env));  // foo.date.year = 2106
    }
}
nil对象

nil是Aviator内置的常量,表示空的值。类似Java的null。

跟null不同点:

  1. Java中null只能使用==、!=的比较运算符。
  2. nil还可以使用>、>=、<、<=等比较运算符

除了nil本身,任何对象都比bil大

nil与String相加时,跟java一样显示为null

日期比较

Aviator不支持日期类型,若要比较日期,需要将日期写成字符串的形式,且要求是如“yyy-MM-dd HH:mm:ss:SS”形式的字符串,否则将报错。

字符串跟java.util.Date比较时将自动转换为Date对象进行比较

public static void main(String[] args) { 
    Map<String, Object> env = new HashMap<String, Object>();
    final Date date = new Date();
    String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS").format(date);
    env.put("date", date);
    env.put("dateStr", dateStr);
    Boolean result = (Boolean) AviatorEvaluator.execute("date==dateStr", env);
    System.out.println(result);  // true
    result = (Boolean) AviatorEvaluator.execute("date > '2010-12-20 00:00:00:00' ", env);
    System.out.println(result);  // true
    result = (Boolean) AviatorEvaluator.execute("date < '2200-12-20 00:00:00:00' ", env);
    System.out.println(result);  // true
    result = (Boolean) AviatorEvaluator.execute("date==date ", env);
    System.out.println(result);  // true
}

即String可以跟String本身比较之外,还能跟nil和Date对象比较。

大数计算和精度

从2.3.0版本开始,aviator支持大数字计算和特定精度的计算

本质就是支持java.math.BigIntegerjava.math.BigDecimal两种类型,这两种类型在aviator中简称为big int和decimal。

public static void main(String[] args) { 
    System.out.println(AviatorEvaluator.exec("99999999999999999999999999999999 + 99999999999999999999999999999999"));
}

结果为类型big int的: 199999999999999999999999999999998

1、字面量表示

big int和decimal的表示与其他数字不同,两条规则:

  1. 以大写字母N为后缀的整数都被认为为big int
  2. 超过long范围的整数字面量都将自动转换为big int
  3. 以大写字母M为后缀的数字都被认为为decimal
2、运算

big int和decimal的运算与其他数字类型long、double没什么区别,操作符一样。

aviator重载了基本算数操作符来支持这两种型类型:

public static void main(String[] args) { 
    Object rt = AviatorEvaluator.exec("9223372036854775807100.356M * 2");
    System.out.println(rt + " " + rt.getClass());  // 18446744073709551614200.712 class java.math.BigDecimal
    rt = AviatorEvaluator.exec("92233720368547758074+1000");
    System.out.println(rt + " " + rt.getClass());  // 92233720368547759074 class java.math.BigInteger
    BigInteger a = new BigInteger(String.valueOf(Long.MAX_VALUE) + String.valueOf(Long.MAX_VALUE));
    BigDecimal b = new BigDecimal("3.2");
    BigDecimal c = new BigDecimal("9999.99999");
    rt = AviatorEvaluator.exec("a+10000000000000000000", a);
    System.out.println(rt + " " + rt.getClass());  // 92233720368547758089223372036854775807 class java.math.BigInteger
    rt = AviatorEvaluator.exec("b+c*2", b, c);
    System.out.println(rt + " " + rt.getClass());  // 20003.19998 class java.math.BigDecimal
    rt = AviatorEvaluator.exec("a*b/c", a, b, c);
    System.out.println(rt + " " + rt.getClass());  // 2.951479054745007313280155218459508E+34 class java.math.BigDecimal
}
3、类型转换和提升

当big int或decimal和其他类型的数字做运算时,按照long < big int < decimal < double的规则做提升。即运算的数字若剋新不一致,结果类型为两者之间更“高”的类型

4、decimal的计算精度

Java的java.math.BigDecimal通过java.math.MathContext支持特定精度的计算,任何涉及到金额的计算都应使用decimal类型。

默认Aviator的计算精度为MathContext.DECIMAL128。可通过AviatorEvaluator.setMathContext(MathContext.DECIMAL64);自定义精度。

seq库

aviator拥有强大的操作集合和数组的seq库。

整个库的风格类似函数式编程中的高阶函数。

在aviator中,数组以及java.util.Collection下的子类都称为seq,可以直接利用seq库进行遍历、过滤、聚合等操作。

public static void main(String[] args) { 
    Map<String, Object> env = new HashMap<String, Object>();
    ArrayList<Integer> list = new ArrayList<Integer>();
    list.add(3);
    list.add(20);
    list.add(10);
    env.put("list", list);
    Object result = AviatorEvaluator.execute("count(list)", env);
    System.out.println(result);  // 3
    result = AviatorEvaluator.execute("reduce(list,+,0)", env);
    System.out.println(result);  // 33
    result = AviatorEvaluator.execute("filter(list,seq.gt(9))", env);
    System.out.println(result);  // [10, 20]
    result = AviatorEvaluator.execute("include(list,10)", env);
    System.out.println(result);  // true
    result = AviatorEvaluator.execute("sort(list)", env);
    System.out.println(result);  // [3, 10, 20]
    AviatorEvaluator.execute("map(list,println)", env);
}
  • 求长度: count(list)
  • 求和: reduce(list,+,0), reduce函数接收三个参数,第一个是seq,第二个是聚合的函数,如+等,第三个是聚合的初始值
  • 过滤: filter(list,seq.gt(9)), 过滤出list中所有大于9的元素并返回集合; seq.gt函数用于生成一个谓词,表示大于某个值
  • 判断元素在不在集合里: include(list,10)
  • 排序: sort(list)
  • 遍历整个集合: map(list,println), map接受的第二个函数将作用于集合中的每个元素,这里简单地调用println打印每个元素
两种运行模式
  • 执行速度优先:默认;AviatorEvaluator.setOptimize(AviatorEvaluator.EVAL);
  • 编译速度优先:不会做编译优化;AviatorEvaluator.setOptimize(AviatorEvaluator.COMPILE);
调试信息

从2.1.1版本开始,Aviator允许设置输出每个表达式生成的字节码

AviatorEvaluator.setTrace(true);

方便用户做跟踪和调试。默认时输出带标准输出,可该百年输出指向:

AviatorEvaluator.setTraceOutputStream(new FileOutputStream(new File("aviator.log")));
内置函数
函数名称说明
sysdate()返回当前日期对象 java.util.Date
rand()返回一个介于 0-1 的随机数,double 类型
print([out],obj)打印对象,如果指定 out,向 out 打印, 否则输出到控制台
println([out],obj)与 print 类似,但是在输出后换行
now()返回 System.currentTimeMillis
long(v)将值的类型转为 long
double(v)将值的类型转为 double
str(v)将值的类型转为 string
date_to_string(date,format)将 Date 对象转化化特定格式的字符串,2.1.1 新增
string_to_date(source,format)将特定格式的字符串转化为 Date 对 象,2.1.1 新增
string.contains(s1,s2)判断 s1 是否包含 s2,返回 Boolean
string.length(s)求字符串长度,返回 Long
string.startsWith(s1,s2)s1 是否以 s2 开始,返回 Boolean
string.endsWith(s1,s2)s1 是否以 s2 结尾,返回 Boolean
string.substring(s,begin[,end])截取字符串 s,从 begin 到 end,如果忽略 end 的话,将从 begin 到结尾,与 java.util.String.substring 一样。
string.indexOf(s1,s2)java 中的 s1.indexOf(s2),求 s2 在 s1 中 的起始索引位置,如果不存在为-1
string.split(target,regex,[limit])Java 里的 String.split 方法一致,2.1.1 新增函数
string.join(seq,seperator)将集合 seq 里的元素以 seperator 为间隔 连接起来形成字符串,2.1.1 新增函数
string.replace_first(s,regex,replacement)Java 里的 String.replaceFirst 方法, 2.1.1 新增
string.replace_all(s,regex,replacement)Java 里的 String.replaceAll 方法 , 2.1.1 新增
math.abs(d)求 d 的绝对值
math.sqrt(d)求 d 的平方根
math.pow(d1,d2)求 d1 的 d2 次方
math.log(d)求 d 的自然对数
math.log10(d)求 d 以 10 为底的对数
math.sin(d)正弦函数
math.cos(d)余弦函数
math.tan(d)正切函数
map(seq,fun)将函数 fun 作用到集合 seq 每个元素上, 返回新元素组成的集合
filter(seq,predicate)将谓词 predicate 作用在集合的每个元素 上,返回谓词为 true 的元素组成的集合
count(seq)返回集合大小
include(seq,element)判断 element 是否在集合 seq 中,返回 boolean 值
sort(seq)排序集合,仅对数组和 List 有效,返回排 序后的新集合
reduce(seq,fun,init)fun 接收两个参数,第一个是集合元素, 第二个是累积的函数,本函数用于将 fun 作用在集合每个元素和初始值上面,返回 最终的 init 值
seq.eq(value)返回一个谓词,用来判断传入的参数是否跟 value 相等,用于 filter 函数,如filter(seq,seq.eq(3)) 过滤返回等于3 的元素组成的集合
seq.neq(value)与 seq.eq 类似,返回判断不等于的谓词
seq.gt(value)返回判断大于 value 的谓词
seq.ge(value)返回判断大于等于 value 的谓词
seq.lt(value)返回判断小于 value 的谓词
seq.le(value)返回判断小于等于 value 的谓词
seq.nil()返回判断是否为 nil 的谓词
seq.exists()返回判断不为 nil 的谓词

本文整理自:https://my.oschina.net/kings0/blog/4710642

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
aviator规则引擎配置是指在使用aviator规则引擎的过程中,对其进行相关参数的设置和调整,以适应具体业务的需求和实际场景的要求。 配置aviator规则引擎通常包括以下几个方面: 1. 规则文件的加载:在使用aviator规则引擎之前,需要将规则文件加载到引擎中。规则文件可以是文本文件,也可以是数据库中的数据。通过适当的配置,可以指定规则文件的路径或者连接信息,使得引擎能够正确地加载和解析规则文件。 2. 规则变量的设置:规则引擎需要获取和设置一系列的规则变量,以进行规则的计算和推理。在配置引擎时,可以指定规则变量的名称、类型和初值,以及变量的作用域和可见性等。这样,在使用规则引擎时可以直接引用规则变量,进行相应的计算和判断。 3. 规则优先级的设定:规则引擎通常会包含多条规则,而这些规则有时候会有互相之间的冲突。通过设定规则的优先级,可以确定规则执行的先后顺序,从而在执行过程中遵循预期的逻辑。一般来说,可以通过给规则设置权重或者指定执行顺序的方式来设定规则的优先级。 4. 规则引擎选项的调整:aviator规则引擎通常提供了一系列的配置选项,用于控制规则的执行模式和行为。比如,可以通过设置最大执行时间、最大递归深度、启用缓存等选项来控制规则的执行效率和安全性。此外,还可以针对debug模式、编译模式和并发模式等方面进行相应的设置。 通过合理的配置,aviator规则引擎可以在各种复杂的场景下发挥出强大的计算和决策能力,提高系统的效率和灵活性。但是需要注意的是,配置规则引擎要根据具体的需求和条件,避免过度的调整和复杂的配置,以免引起不必要的性能开销或者错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值