程序与技术分享:Aviator表达式求值引擎开源框架

简介: 程序与技术分享:Aviator表达式求值引擎开源框架

简介?


Aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。现在已经有很多开源可用的java表达式求值引擎,为什么还需要Avaitor呢?


Aviator的设计目标是轻量级和高性能 ,相比于Groovy、JRuby的笨重,Aviator非常小,加上依赖包也才450K,不算依赖包的话只有70K;当然,Aviator的语法是受限的,它不是一门完整的语言,而只是语言的一小部分集合。


其次,Aviator的实现思路与其他轻量级的求值器很不相同,其他求值器一般都是通过解释的方式运行,而Aviator则是直接将表达式编译成Java字节码,交给JVM去执行。简单来说,Aviator的定位是介于Groovy这样的重量级脚本语言和IKExpression这样的轻量级表达式引擎之间。


特性?


Aviator的特性


支持大部分运算操作符,包括算术操作符、关系运算符、逻辑操作符、正则匹配操作符(=~)、三元表达式?: ,并且支持操作符的优先级和括号强制优先级,具体请看后面的操作符列表。


支持函数调用和自定义函数


支持正则表达式匹配,类似Ruby、Perl的匹配语法,并且支持类Ruby的$digit指向匹配分组。


自动类型转换,当执行操作的时候,会自动判断操作数类型并做相应转换,无法转换即抛异常。


支持传入变量,支持类似a.b.c的嵌套变量访问。


性能优秀


Aviator的限制:


没有if else、do while等语句,没有赋值语句,仅支持逻辑表达式、算术表达式、三元表达式和正则匹配。


没有位运算符


整体结构?


Aviator的结构非常简单,一个典型的求值器的结构


依赖包?


commons-beanutils和commons-logging


使用手册?


执行表达式?


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);


}


}


细心的朋友肯定注意到结果是Long,而不是Integer。这是因为Aviator的数值类型仅支持Long和Double,任何整数都将转换成Long,任何浮点数都将转换为Double,包括用户传入的变量数值。这个例子的打印结果将是正确答案6。


使用变量?


想让Aviator对你say hello吗?很简单,传入你的名字,让Aviator负责字符串的相加:


import com.googlecode.aviator.AviatorEvaluator;


public class SayHello {


public static void main(String【】 args) {


if (args.length [span class="pln"> 1) {


System.err.print("Usesage: Java SayHello yourname");


}


String yourname = args【0】;


Map[span class="typ">String, ObjectString, Object

env.put("yourname", yourname);


String result = (String) AviatorEvaluator.execute(" 'hello ' + yourname ", env);


System.out.println(result);


}


}


上面的例子演示了怎么向表达式传入变量值,表达式中的yourname是一个变量,默认为null,通过传入Map的变量绑定环境,将yourname设置为你输入的名称。env的key是变量名,//代码效果参考:http://www.jhylw.com.cn/441837179.html

value是变量的值。

上面例子中的'hello '是一个Aviator的String,Aviator的String是任何用单引号或者双引号括起来的字符序列,String可以比较大小(基于unicode顺序),可以参与正则匹配,可以与任何对象相加,任何对象与String相加结果为String。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


调用函数?


Aviator支持函数调用,函数调用的风格类似lua,下面的例子获取字符串的长度:


AviatorEvaluator.execute("string.length('hello')");


string.length('hello')是一个函数调用,string.length是一个函数,'hello'是调用的参数。


再用string.substring来截取字符串:


AviatorEvaluator.execute("string.contains(/"test/",string.substring('hello',1,2))");


通过string.substring('hello',1,2)获取字符串'e',然后通过函数string.contains判断e是否在'test'中。可以看到,函数可以嵌套调用。


Aviator的内置函数列表请看后面。


自定义函数?


Aviator除了内置的函数之外,还允许用户自定义函数,只要实现com.googlecode.aviator.runtime.type.AviatorFunction接口,并注册到AviatorEvaluator即可使用


public interface AviatorFunction {


/


Get the function name



@return


/


public String getName();


/


call function



@param env


Variable environment


@param args


Function arguments


@return


/


public AviatorObject call(Map[span class="typ">String, Object

}


可以看一个例子,我们实现一个add函数来做数值的相加:


import com.googlecode.aviator.runtime.function.FunctionUtils;


import com.googlecode.aviator.runtime.type.AviatorDouble;


import com.googlecode.aviator.runtime.type.AviatorFunction;


import com.googlecode.aviator.runtime.type.AviatorObject;


public class AddFunction implements AviatorFunction {


public AviatorObject call(Map[span class="typ">String, Object

if (args.length != 2) {


throw new IllegalArgumentException("Add only supports two arguments");


}


Number left = FunctionUtils.getNumberValue(0, args, env);


Number right = FunctionUtils.getNumberValue(1, args, env);


return new AviatorDouble(left.doubleValue() + right.doubleValue());


}


public String getName() {


return "add";


}


}


注册到AviatorEvaluator并调用如下:


//注册函数


AviatorEvaluator.addFunction(new AddFunction());


System.out.println(AviatorEvaluator.execute("add(1,2)"));


System.out.println(AviatorEvaluator.execute("add(add(1,2),100)"));


注册函数通过AviatorEvaluator.addFunction方法,移除可以通过removeFunction。


编译表达式?


上面提到的例子都是直接执行表达式,事实上Aviator背后都帮你做了编译并执行的工作。你可以自己先编译表达式,返回一个编译的结果,然后传入不同的env来复用编译结果,提高性能,这是更推荐的使用方式:


import java.util.HashMap;


import java.util.Map;


import com.googlecode.aviator.AviatorEvaluator;


import com.googlecode.aviator.Expression;


public class CompileExample {


public static void main(String【】 args) {


String expression = "a-(b-c)>100";


// 编译表达式


Expression compiledExp = AviatorEvaluator.compile(expression);


Map[span class="typ">String, ObjectString, Object

env.put("a", 100.3);


env.put("b", 45);


env.put("c", -199.100);


// 执行表达式


Boolean result = (Boolean) compiledExp.execute(env);


System.out.println(result);


}


}


通过compile方法可以将表达式编译成Expression的中间对象,当要执行表达式的时候传入env并调用Expression的execute方法即可。表达式中使用了括号来强制优先级,这个例子还使用了>用于比较数值大小,比较运算符!=、==、>、>=、<、<=不仅可以用于数值,也可以用于String、Pattern、Boolean等等,甚至是任何用户传入的两个都实现了java.lang。Comparable接口的对象之间。


编译后的结果你可以自己缓存,也可以交给Aviator帮你缓存,AviatorEvaluator内部有一个全局的缓存池,如果你决定缓存编译结果,可以通过:


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,一个例子:


import java.util.ArrayList;


import java.util.Date;


import java.util.HashMap;


import java.util.List;


import java.util.Map;


import com.googlecode.aviator.AviatorEvaluator;


public class CollectionExample {


public static void main(String【】 args) {


final List[span class="typ">StringString

list.add("hello");


list.add(" world");


final int【】 array = new int【3】;


array【0】 = 0;


array【1】 = 1;


array【2】 = 3;


final Map[span class="typ">String, DateString, Date

map.put("date", new Date());


&

相关文章
|
缓存 安全 Java
|
存储 安全 Java
BlockingQueue(阻塞队列)基本使用指南
BlockingQueue(阻塞队列)基本使用指南
607 1
|
6月前
|
人工智能 JSON Java
AI时代,我们为何重写规则引擎?—— QLExpress4 重构之路
AI时代下,规则引擎的需求反而更旺盛。QLExpress4 通过全面重构,在性能、可观测性和AI友好性上大幅提升。
1906 15
AI时代,我们为何重写规则引擎?—— QLExpress4 重构之路
|
10月前
|
XML 人工智能 Java
Spring Boot集成Aviator实现参数校验
Aviator是一个高性能、轻量级的Java表达式求值引擎,适用于动态表达式计算。其特点包括支持多种运算符、函数调用、正则匹配、自动类型转换及嵌套变量访问,性能优异且依赖小。适用于规则引擎、公式计算和动态脚本控制等场景。本文介绍了如何结合Aviator与AOP实现参数校验,并附有代码示例和仓库链接。
627 0
|
自然语言处理 安全 Java
Aviator Java 表达式引擎
AviatorScript 是一门高性能、轻量级寄宿于 JVM 之上的脚本语言。
665 10
|
安全 Java 编译器
springboot 整合表达式计算引擎 Aviator 使用示例详解
本文详细介绍了Google Aviator 这款高性能、轻量级的 Java 表达式求值引擎
2317 6
|
SQL 存储 大数据
Flink 基础详解:大数据处理的强大引擎
Apache Flink 是一个分布式流批一体化的开源平台,专为大规模数据处理设计。它支持实时流处理和批处理,具有高吞吐量、低延迟特性。Flink 提供统一的编程抽象,简化大数据应用开发,并在流处理方面表现卓越,广泛应用于实时监控、金融交易分析等场景。其架构包括 JobManager、TaskManager 和 Client,支持并行度、水位线、时间语义等基础属性。Flink 还提供了丰富的算子、状态管理和容错机制,如检查点和 Savepoint,确保作业的可靠性和一致性。此外,Flink 支持 SQL 查询和 CDC 功能,实现实时数据捕获与同步,广泛应用于数据仓库和实时数据分析领域。
10957 42
|
SQL Java 数据库连接
如何在 Java 代码中使用 JSqlParser 解析复杂的 SQL 语句?
大家好,我是 V 哥。JSqlParser 是一个用于解析 SQL 语句的 Java 库,可将 SQL 解析为 Java 对象树,支持多种 SQL 类型(如 `SELECT`、`INSERT` 等)。它适用于 SQL 分析、修改、生成和验证等场景。通过 Maven 或 Gradle 安装后,可以方便地在 Java 代码中使用。
4686 11
|
JSON 自然语言处理 Java
这款轻量级 Java 表达式引擎,真不错!
AviatorScript 是一个高性能、轻量级的脚本语言,基于 JVM(包括 Android 平台)。它支持数字、字符串、正则表达式、布尔值等基本类型,以及所有 Java 运算符。主要特性包括函数式编程、大整数和高精度运算、完整的脚本语法、丰富的内置函数和自定义函数支持。适用于规则判断、公式计算、动态脚本控制等场景。
|
数据可视化 算法 Java
JAVA规则引擎工具
本文介绍了六款常用的Java规则引擎:Drools、IBM ODM、Easy Rules、jBPM、OpenL Tablets 和 Apache Camel。每款引擎都有其独特的特点和适用场景,如Drools的高效规则匹配、IBM ODM的Web界面管理、Easy Rules的轻量级特性、jBPM的流程管理、OpenL Tablets的Excel规则定义以及Apache Camel的路由和规则结合。选择合适的规则引擎可以显著提高系统的灵活性和可维护性。
1637 0

热门文章

最新文章