在实际的 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 的核心,负责编译表达式,计算表达式结果等。
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
}
}
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);
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);
二、AbstractFunction 和 AbstractVariadicFunction
在 Aviator 中,AbstractFunction 和 AbstractVariadicFunction 都用于 实现自定义函数,但它们的设计目标不同:
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 的天。