Google Aviator 使用及入门记录

8 阅读5分钟

在实际的 Java 开发中,业务规则可能会频繁变化,如果这些规则全部写在 Java 代码中,一旦规则变化,就需要修改代码、重新编译、重新发布系统,这在复杂系统中往往成本很高。因此,很多系统都会引入表达式引擎来解决这一问题。Google Aviator 就是 Java 生态中一个非常流行的高性能表达式引擎。

本文将从 Aviator 的基础使用、核心 API、SpringBoot 集成以及实际业务场景等方面,系统介绍 Aviator 的使用方式。

一、Aviator 的基础使用

使用 Aviator 时,首先需要引入相关依赖:

<dependency>
    <groupId>com.googlecode.aviator</groupId>
    <artifactId>aviator</artifactId>
    <version>{version}</version>
</dependency>

Aviator的使用都是集中通过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);
    }
}

1、AviatorEvaluator类

AviatorEvaluator是整个 Aviator 的核心,负责编译表达式,计算表达式结果等。

  1. AviatorEvaluator.execute:用于生成表达式的计算结果
static Object execute(String expression) //执行表达式,不使用缓存和参数。
static Object execute(String expression, Map<String,Object> env) //使用参数执行表达式
static Object execute(String expression, Map<String,Object> env, boolean cached) //使用参数执行表达式,cached用于决定是否使用缓存,以便在下次计算同一个表达式时,使用缓存结果

带参表达式计算示例:

Map<String, Object> env = new HashMap<>();  
env.put("a", 10);  
env.put("b", 20);  
Long result = (Long) AviatorEvaluator.execute("a + b", env);

需要注意的是,数值计算结果类型只有Long、Double、big int、decimal四种类型,如果不确定返回值类型,可以使用条件语句判断:

Object result = AviatorEvaluator.execute(expression);  
  
if (result instanceof Number) {  
    Number num = (Number) result;  
  
    if (num instanceof Long) {  
    // long  
    } else if (num instanceof Double) {  
    // double  
    } else if (num instanceof BigInteger) {  
    // big integer  
    } else if (num instanceof BigDecimal) {  
    // big decimal  
    }  
}
  1. AviatorEvaluator.compile:用于将表达式编译为Expression对象
static Expression compile(String expression) // 将表达式编译为表达式对象,不进行缓存
static Expression compile(String expression, boolean cached) // 将表达式编译为表达式对象,并进行缓存,下次编译同一个表达式时,直接使用缓存结果

compile主要用于表达式需要 频繁执行的情况,节省表达式频繁编译的时间,编译表达式并执行计算的示例如下:

Expression exp = AviatorEvaluator.compile("a + b");  
Map<String, Object> env = new HashMap<>();  
env.put("a", 10);  
env.put("b", 20);  
Long result = (Long) exp.execute(env);
  1. AviatorEvaluator.addFunction:用于添加自定义函数

Aviator 内置了很多计算函数,如:

  • abs(x):返回 x 的绝对值。
  • ceil(x):返回大于等于 x 的最小整数。

但如果我们需要自定义一个新的函数,就需要通过addFunction添加,添加后AviatorEvaluator才能识别该函数。添加自定义函数的示例如下:

首先需要自定义一个函数类,需要继承AbstractFunction

class MaxFunction extends AbstractFunction {

    @Override
    public AviatorObject call(Map<String, Object> env,
                              AviatorObject arg1,
                              AviatorObject arg2) {

        Number a = (Number) arg1.getValue(env);
        Number b = (Number) arg2.getValue(env);
        double result = Math.max(a.doubleValue(), b.doubleValue());
        return new AviatorDouble(result);
    }

    //声明函数名称
    @Override
    public String getName() {
        return "max";
    }
}

然后再通过execute调用该函数:

Map<String, Object> env = new HashMap<>();
env.put("a", 10);
env.put("b", 20);
AviatorEvaluator.addFunction(new MaxFunction()); //添加max函数
Double result = (Double) AviatorEvaluator.execute("max(a, b)", env);

二、AbstractFunctionAbstractVariadicFunction

在 Aviator 中,AbstractFunctionAbstractVariadicFunction 都用于 实现自定义函数,但它们的设计目标不同:

  • AbstractFunction:用于 固定参数数量的函数
  • AbstractVariadicFunction:用于 可变参数(不定参数)函数

AbstractFunction所包含的函数如下,每个函数都有固定的参数个数,因此重载call函数时,必须确定所需的参数个数:

AviatorObject call(Map<String,Object> env)
AviatorObject call(Map<String,Object> env, AviatorObject arg1)
AviatorObject call(Map<String,Object> env, AviatorObject arg1, AviatorObject arg2)
AviatorObject call(Map<String,Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3)
……

AbstractVariadicFunction适用于可变参数个数的函数,类似于:

void sum(int... nums) // nums个数可以是任意个

因此, AbstractVariadicFunction增加了variadicCall

AviatorObject variadicCall(Map<String,Object> env, AviatorObject... args)

以下是一个使用AbstractFunction实现 sum(a,b,c,d,...) 函数的示例

public class SumFunction extends AbstractVariadicFunction {

    @Override
    public AviatorObject call(Map<String,Object> env, AviatorObject... args) {

        double sum = 0;

        for (AviatorObject arg : args) {
            Number n = (Number) arg.getValue(env);
            sum += n.doubleValue();
        }

        return new AviatorDouble(sum);
    }

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

三、Aviator表达式

参考java 表达式引擎概览-02-google 表达式引擎 Aviator 入门介绍

Aviator 表达式支持很多内置函数,包括:

数学函数

  • abs(x):返回 x 的绝对值。
  • ceil(x):返回大于等于 x 的最小整数。
  • floor(x):返回小于等于 x 的最大整数。
  • round(x):返回四舍五入后的整数。
  • max(x, y):返回 x 和 y 中的最大值。
  • min(x, y):返回 x 和 y 中的最小值。
  • sqrt(x):返回 x 的平方根。
  • pow(x, y):返回 x 的 y 次方。
  • random():返回一个随机数。

字符串函数

  • string.length(s):返回字符串 s 的长度。
  • string.contains(s, sub):判断字符串 s 是否包含子串 sub。
  • string.startsWith(s, prefix):判断字符串 s 是否以 prefix 开头。
  • string.endsWith(s, suffix):判断字符串 s 是否以 suffix 结尾。
  • string.substring(s, begin, end):返回字符串 s 从 begin 到 end 的子串。
  • string.replace(s, target, replacement):将字符串 s 中的 target 替换为 replacement。
  • string.upper(s):将字符串 s 转换为大写。
  • string.lower(s):将字符串 s 转换为小写。

集合函数

  • list.size(list):返回集合 list 的大小。
  • list.contains(list, element):判断集合 list 是否包含元素 element。
  • list.get(list, index):返回集合 list 中指定索引位置的元素。
  • list.add(list, element):向集合 list 中添加元素 element。
  • list.remove(list, element):从集合 list 中移除元素 element。

逻辑函数

  • and(x, y):返回 x 和 y 的逻辑与。
  • or(x, y):返回 x 和 y 的逻辑或。
  • not(x):返回 x 的逻辑非。

日期时间函数

  • date.now():返回当前时间。
  • date.format(date, pattern):按照指定格式 pattern 格式化日期 date。
  • date.parse(dateString, pattern):按照指定格式 pattern 解析日期字符串 dateString。
  • date.year(date):返回日期 date 的年份。
  • date.month(date):返回日期 date 的月份。
  • date.day(date):返回日期 date 的天。